public final static String bt_product_telebt = bt_product_telebt();
-// public static AltosBTKnown bt_known = new AltosBTKnown();
+ public static AltosBTKnown bt_known = new AltosBTKnown();
}
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)
writer.close();
} catch (FileNotFoundException ee) {
JOptionPane.showMessageDialog(frame,
- file.getName(),
+ ee.getMessage(),
"Cannot open file",
JOptionPane.ERROR_MESSAGE);
}
}
} 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) {
JRadioButton serial_debug;
-// BLUETOOTH
-// JButton manage_bluetooth;
+ JButton manage_bluetooth;
JButton manage_frequencies;
final static String[] font_size_names = { "Small", "Medium", "Large" };
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() {
}
});
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;
}
} catch (FileNotFoundException fe) {
JOptionPane.showMessageDialog(frame,
- filename,
+ fe.getMessage(),
"Cannot open file",
JOptionPane.ERROR_MESSAGE);
}
public abstract int getSerial();
public abstract String getPath();
public abstract boolean matchProduct(int product);
+ public abstract String getErrorString();
public SWIGTYPE_p_altos_file open();
}
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;
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;
}
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");
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);
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);
}
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;
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);
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) {
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,
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) {
FileInputStream in = new FileInputStream(file);
records = new AltosTelemetryIterable(in);
} else {
- throw new FileNotFoundException();
+ throw new FileNotFoundException(filename);
}
try {
new AltosGraphUI(records, filename);
}
} catch (FileNotFoundException fe) {
JOptionPane.showMessageDialog(null,
- filename,
+ fe.getMessage(),
"Cannot open file",
JOptionPane.ERROR_MESSAGE);
}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
/* 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";
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");
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);
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");
}
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) {
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) {
}
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());
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) {
});
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();
new AltosSiteMapPreload(AltosUI.this);
}
+ void LaunchController() {
+ new AltosLaunchUI(AltosUI.this);
+ }
+
/*
* Replay a flight from telemetry data
*/
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;
}
}
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;
}
}
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;
}
}
}
+ 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);
}
AltosIdleMonitorUI.java \
AltosIgnite.java \
AltosIgniteUI.java \
+ AltosLaunch.java \
+ AltosLaunchUI.java \
AltosInfoTable.java \
AltosKML.java \
AltosLanded.java \
AltosGraphUI.java \
AltosDataChooser.java \
AltosVersion.java \
- AltosVoice.java
+ AltosVoice.java \
+ $(altosui_BT)
JFREECHART_CLASS= \
jfreechart.jar
{
}
+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
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)
{
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;
}
#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;
#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);
#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);
#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);
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)
{
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;
free(usbdevs);
}
-#if HAS_BLUETOOTH
struct altos_bt_list {
inquiry_info *ii;
int sock;
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;
(struct sockaddr *)&addr,
sizeof(addr));
if (status < 0) {
- perror("connect");
+ altos_set_last_posix_error();
goto no_link;
}
sleep(1);
no_file:
return NULL;
}
-#endif /* HAS_BLUETOOTH */
#endif
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
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)
{
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;
}
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;
}
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;
port, &port_len);
RegCloseKey(dev_key);
if (result != 0) {
+ altos_set_last_windows_error();
printf("failed to get PortName\n");
continue;
}
sizeof(friendlyname),
&friendlyname_len))
{
+ altos_set_last_windows_error();
printf("Failed to get friendlyname\n");
continue;
}
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;
}
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;
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;
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;
}
}
0, NULL, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, NULL);
if (file->handle == INVALID_HANDLE_VALUE) {
+ altos_set_last_windows_error();
free(file);
return NULL;
}
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (!GetCommState(file->handle, &dcbSerialParams)) {
+ altos_set_last_windows_error();
CloseHandle(file->handle);
free(file);
return NULL;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
if (!SetCommState(file->handle, &dcbSerialParams)) {
+ altos_set_last_windows_error();
CloseHandle(file->handle);
free(file);
return NULL;
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
//%mutable;
};
+struct altos_error {
+ int code;
+ char string[1024];
+};
+
#define LIBALTOS_SUCCESS 0
#define LIBALTOS_ERROR -1
#define LIBALTOS_TIMEOUT -2
PUBLIC void
altos_fini(void);
+PUBLIC void
+altos_get_last_error(struct altos_error *error);
+
PUBLIC struct altos_list *
altos_list_start(void);
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);
PUBLIC struct altos_file *
altos_bt_open(struct altos_bt_device *device);
-#endif
-
#endif /* _LIBALTOS_H_ */
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
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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.
- */
-
-/* Defines for the 25LC1024 1Mbit SPI Bus Serial EEPROM */
-
-#ifndef _25LC1024_H_
-#define _25LC1024_H_
-
-#define EE_READ 0x03
-#define EE_WRITE 0x02
-#define EE_WREN 0x06
-#define EE_WRDI 0x04
-#define EE_RDSR 0x05
-#define EE_WRSR 0x01
-#define EE_PE 0x42
-#define EE_SE 0xd8
-#define EE_CE 0xc7
-#define EE_RDID 0xab
-#define EE_DPD 0xb9
-
-#define EE_STATUS_WIP (1 << 0)
-#define EE_STATUS_WEL (1 << 1)
-#define EE_STATUS_BP0 (1 << 2)
-#define EE_STATUS_BP1 (1 << 3)
-#define EE_STATUS_WPEN (1 << 7)
-
-#endif /* _25LC1024_H_ */
# 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
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
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
+++ /dev/null
-#
-# 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:
+++ /dev/null
-/*-------------------------------------------------------------------------
-
- _bp.c :- just declares bp as a variable
-
- Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999)
-
- This library is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- This library 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 Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this program; if not, write to the Free Software
- Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- In other words, you are welcome to use, share and improve this program.
- You are forbidden to forbid anyone else to use, share and improve
- what you give them. Help stamp out software-hoarding!
--------------------------------------------------------------------------*/
-
-__data unsigned char bp ;
+++ /dev/null
-/*max error 3.197865153490684 at 0.782%. Average error 0.260150920474668*/
-#define NALT 129
-#define ALT_FRAC_BITS 8
- 15835, /* 10.56 kPa 0.000% */
- 15332, /* 11.42 kPa 0.781% */
- 14868, /* 12.29 kPa 1.563% */
- 14435, /* 13.16 kPa 2.344% */
- 14030, /* 14.02 kPa 3.125% */
- 13649, /* 14.90 kPa 3.906% */
- 13290, /* 15.76 kPa 4.688% */
- 12950, /* 16.63 kPa 5.469% */
- 12627, /* 17.50 kPa 6.250% */
- 12320, /* 18.37 kPa 7.031% */
- 12027, /* 19.24 kPa 7.813% */
- 11747, /* 20.10 kPa 8.594% */
- 11479, /* 20.97 kPa 9.375% */
- 11222, /* 21.84 kPa 10.156% */
- 10975, /* 22.71 kPa 10.938% */
- 10736, /* 23.58 kPa 11.719% */
- 10504, /* 24.44 kPa 12.500% */
- 10278, /* 25.31 kPa 13.281% */
- 10059, /* 26.18 kPa 14.063% */
- 9846, /* 27.05 kPa 14.844% */
- 9638, /* 27.91 kPa 15.625% */
- 9435, /* 28.78 kPa 16.406% */
- 9237, /* 29.65 kPa 17.188% */
- 9044, /* 30.52 kPa 17.969% */
- 8855, /* 31.39 kPa 18.750% */
- 8670, /* 32.26 kPa 19.531% */
- 8490, /* 33.13 kPa 20.313% */
- 8313, /* 33.99 kPa 21.094% */
- 8140, /* 34.86 kPa 21.875% */
- 7970, /* 35.73 kPa 22.656% */
- 7803, /* 36.60 kPa 23.438% */
- 7640, /* 37.47 kPa 24.219% */
- 7480, /* 38.33 kPa 25.000% */
- 7322, /* 39.20 kPa 25.781% */
- 7168, /* 40.07 kPa 26.563% */
- 7016, /* 40.94 kPa 27.344% */
- 6867, /* 41.80 kPa 28.125% */
- 6720, /* 42.67 kPa 28.906% */
- 6575, /* 43.54 kPa 29.688% */
- 6433, /* 44.41 kPa 30.469% */
- 6294, /* 45.28 kPa 31.250% */
- 6156, /* 46.15 kPa 32.031% */
- 6020, /* 47.01 kPa 32.813% */
- 5887, /* 47.88 kPa 33.594% */
- 5755, /* 48.75 kPa 34.375% */
- 5625, /* 49.62 kPa 35.156% */
- 5497, /* 50.49 kPa 35.938% */
- 5371, /* 51.35 kPa 36.719% */
- 5247, /* 52.22 kPa 37.500% */
- 5124, /* 53.09 kPa 38.281% */
- 5003, /* 53.96 kPa 39.063% */
- 4883, /* 54.83 kPa 39.844% */
- 4765, /* 55.69 kPa 40.625% */
- 4648, /* 56.56 kPa 41.406% */
- 4533, /* 57.43 kPa 42.188% */
- 4419, /* 58.30 kPa 42.969% */
- 4307, /* 59.17 kPa 43.750% */
- 4196, /* 60.03 kPa 44.531% */
- 4086, /* 60.90 kPa 45.313% */
- 3977, /* 61.77 kPa 46.094% */
- 3870, /* 62.63 kPa 46.875% */
- 3764, /* 63.51 kPa 47.656% */
- 3659, /* 64.38 kPa 48.438% */
- 3555, /* 65.24 kPa 49.219% */
- 3453, /* 66.11 kPa 50.000% */
- 3351, /* 66.98 kPa 50.781% */
- 3250, /* 67.85 kPa 51.563% */
- 3151, /* 68.72 kPa 52.344% */
- 3052, /* 69.58 kPa 53.125% */
- 2955, /* 70.45 kPa 53.906% */
- 2858, /* 71.32 kPa 54.688% */
- 2763, /* 72.19 kPa 55.469% */
- 2668, /* 73.06 kPa 56.250% */
- 2574, /* 73.92 kPa 57.031% */
- 2482, /* 74.79 kPa 57.813% */
- 2390, /* 75.66 kPa 58.594% */
- 2298, /* 76.52 kPa 59.375% */
- 2208, /* 77.40 kPa 60.156% */
- 2119, /* 78.26 kPa 60.938% */
- 2030, /* 79.13 kPa 61.719% */
- 1942, /* 80.00 kPa 62.500% */
- 1855, /* 80.87 kPa 63.281% */
- 1769, /* 81.74 kPa 64.063% */
- 1683, /* 82.60 kPa 64.844% */
- 1598, /* 83.47 kPa 65.625% */
- 1514, /* 84.34 kPa 66.406% */
- 1430, /* 85.21 kPa 67.188% */
- 1347, /* 86.08 kPa 67.969% */
- 1265, /* 86.94 kPa 68.750% */
- 1184, /* 87.81 kPa 69.531% */
- 1103, /* 88.68 kPa 70.313% */
- 1023, /* 89.55 kPa 71.094% */
- 943, /* 90.41 kPa 71.875% */
- 864, /* 91.28 kPa 72.656% */
- 786, /* 92.15 kPa 73.438% */
- 708, /* 93.02 kPa 74.219% */
- 631, /* 93.89 kPa 75.000% */
- 554, /* 94.76 kPa 75.781% */
- 478, /* 95.63 kPa 76.563% */
- 403, /* 96.49 kPa 77.344% */
- 328, /* 97.36 kPa 78.125% */
- 254, /* 98.23 kPa 78.906% */
- 180, /* 99.10 kPa 79.688% */
- 106, /* 99.97 kPa 80.469% */
- 34, /* 100.83 kPa 81.250% */
- -39, /* 101.70 kPa 82.031% */
- -111, /* 102.57 kPa 82.813% */
- -182, /* 103.44 kPa 83.594% */
- -253, /* 104.30 kPa 84.375% */
- -323, /* 105.17 kPa 85.156% */
- -393, /* 106.04 kPa 85.938% */
- -462, /* 106.91 kPa 86.719% */
- -531, /* 107.78 kPa 87.500% */
- -600, /* 108.65 kPa 88.281% */
- -668, /* 109.51 kPa 89.063% */
- -736, /* 110.38 kPa 89.844% */
- -803, /* 111.25 kPa 90.625% */
- -870, /* 112.12 kPa 91.406% */
- -936, /* 112.99 kPa 92.188% */
- -1002, /* 113.85 kPa 92.969% */
- -1068, /* 114.72 kPa 93.750% */
- -1133, /* 115.59 kPa 94.531% */
- -1198, /* 116.46 kPa 95.313% */
- -1262, /* 117.33 kPa 96.094% */
- -1326, /* 118.19 kPa 96.875% */
- -1389, /* 119.06 kPa 97.656% */
- -1453, /* 119.93 kPa 98.438% */
- -1516, /* 120.80 kPa 99.219% */
- -1578, /* 121.67 kPa 100.000% */
+++ /dev/null
-#!/bin/sh
-
-autoimport ParseArgs;
-
-void
-write_ucs2(string a, string description)
-{
- int len = String::length(a);
-
- printf("/* %s */\n", description);
- printf("#define AO_%s_LEN 0x%02x\n", description, len * 2 + 2);
- printf("#define AO_%s_STRING \"%s\"\n", description, a);
- printf("#define AO_%s_UCS2", description);
- for (int i = 0; i < len; i++) {
- int c = a[i];
- if (i > 0)
- printf(",");
- if (0x20 <= c && c < 128)
- printf(" '%c', 0", c);
- else
- printf(" LE_WORD(0x%04x),", c);
- }
- printf("\n\n");
-}
-
-void
-write_string(string a, string description)
-{
- printf ("/* %s */\n", description);
- printf ("#define AO_%s_STRING \"%s\"\n", description, a);
-}
-
-void
-write_int(int a, string description)
-{
- printf ("/* %s */\n", description);
- printf ("#define AO_%s_NUMBER %d\n\n", description, a);
-}
-
-void
-write_hex(int a, string description)
-{
- printf ("/* %s */\n", description);
- printf ("#define AO_%s_NUMBER 0x%04x\n\n", description, a);
-}
-
-string manufacturer = "altusmetrum.org";
-string product = "TeleMetrum";
-string version = "0.0";
-int serial = 1;
-int user_argind = 0;
-int id_product = 0x000a;
-
-argdesc argd = {
- .args = {
- {
- .var = { .arg_string = &manufacturer },
- .abbr = 'm',
- .name = "manufacturer",
- .expr_name = "manf",
- .desc = "Manufacturer name." },
- {
- .var = { .arg_string = &product },
- .abbr = 'p',
- .name = "product",
- .expr_name = "prod",
- .desc = "Product name." },
- {
- .var = { .arg_int = &id_product },
- .abbr = 'i',
- .name = "id_product",
- .expr_name = "id_p",
- .desc = "Product ID." },
- {
- .var = { .arg_int = &serial },
- .abbr = 's',
- .name = "serial",
- .expr_name = "number",
- .desc = "Serial number." },
- {
- .var = { .arg_string = &version },
- .abbr = 'v',
- .name = "version",
- .expr_name = "string",
- .desc = "Program version." },
- },
- .prog_name = "usb descriptors",
-};
-
-void
-main()
-{
- string[dim(argv)-1] nargv = {[n] = argv[n+1]};
- parseargs(&argd, &nargv);
- write_ucs2(manufacturer, "iManufacturer");
- write_ucs2(product, "iProduct");
- write_ucs2(sprintf("%06d", serial), "iSerial");
- write_int(serial, "iSerial");
- write_hex(id_product, "idProduct");
- write_string(version, "iVersion");
-}
-
-main();
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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_H_
-#define _AO_H_
-
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <stddef.h>
-#include "cc1111.h"
-#include "ao_pins.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)
-
-/* 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 */
- uint8_t task_id; /* unique id */
- __code char *name; /* task name */
- uint8_t stack[AO_STACK_SIZE]; /* saved stack */
-};
-
-extern __xdata struct ao_task *__data ao_cur_task;
-
-#define AO_NUM_TASKS 16 /* maximum number of tasks */
-#define AO_NO_TASK 0 /* no task id */
-
-/*
- ao_task.c
- */
-
-/* Suspend the current task until wchan is awoken.
- * returns:
- * 0 on normal wake
- * 1 on alarm
- */
-uint8_t
-ao_sleep(__xdata void *wchan);
-
-/* Wake all tasks sleeping on wchan */
-void
-ao_wakeup(__xdata void *wchan);
-
-/* set an alarm to go off in 'delay' ticks */
-void
-ao_alarm(uint16_t delay);
-
-/* Yield the processor to another task */
-void
-ao_yield(void) __naked;
-
-/* Add a task to the run queue */
-void
-ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant;
-
-/* Terminate the current task */
-void
-ao_exit(void);
-
-/* Dump task info to console */
-void
-ao_task_info(void);
-
-/* Start the scheduler. This will not return */
-void
-ao_start_scheduler(void);
-
-/*
- * ao_panic.c
- */
-
-#define AO_PANIC_NO_TASK 1 /* AO_NUM_TASKS is not large enough */
-#define AO_PANIC_DMA 2 /* Attempt to start DMA while active */
-#define AO_PANIC_MUTEX 3 /* Mis-using mutex API */
-#define AO_PANIC_EE 4 /* Mis-using eeprom API */
-#define AO_PANIC_LOG 5 /* Failing to read/write log data */
-#define AO_PANIC_CMD 6 /* Too many command sets registered */
-#define AO_PANIC_STDIO 7 /* Too many stdio handlers registered */
-#define AO_PANIC_REBOOT 8 /* Reboot failed */
-#define AO_PANIC_FLASH 9 /* Invalid flash part (or wrong blocksize) */
-#define AO_PANIC_USB 10 /* Trying to send USB packet while busy */
-#define AO_PANIC_BT 11 /* Communications with bluetooth device failed */
-
-/* Stop the operating system, beeping and blinking the reason */
-void
-ao_panic(uint8_t reason);
-
-/*
- * ao_timer.c
- */
-
-/* Our timer runs at 100Hz */
-#define AO_HERTZ 100
-#define AO_MS_TO_TICKS(ms) ((ms) / (1000 / AO_HERTZ))
-#define AO_SEC_TO_TICKS(s) ((s) * AO_HERTZ)
-
-/* Returns the current time in ticks */
-uint16_t
-ao_time(void);
-
-/* Suspend the current task until ticks time has passed */
-void
-ao_delay(uint16_t ticks);
-
-/* Set the ADC interval */
-void
-ao_timer_set_adc_interval(uint8_t interval) __critical;
-
-/* Timer interrupt */
-void
-ao_timer_isr(void) __interrupt 9;
-
-/* Initialize the timer */
-void
-ao_timer_init(void);
-
-/* Initialize the hardware clock. Must be called first */
-void
-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))
-
-
-/*
- * A/D data is stored in a ring, with the next sample to be written
- * at ao_adc_head
- */
-extern volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING];
-extern volatile __data uint8_t ao_adc_head;
-#if HAS_ACCEL_REF
-extern volatile __xdata uint16_t ao_accel_ref[AO_ADC_RING];
-#endif
-
-/* Trigger a conversion sequence (called from the timer interrupt) */
-void
-ao_adc_poll(void);
-
-/* Suspend the current task until another A/D sample is converted */
-void
-ao_adc_sleep(void);
-
-/* Get a copy of the last complete A/D sample set */
-void
-ao_adc_get(__xdata struct ao_adc *packet);
-
-/* The A/D interrupt handler */
-
-void
-ao_adc_isr(void) __interrupt 1;
-
-/* Initialize the A/D converter */
-void
-ao_adc_init(void);
-
-#endif /* HAS_ADC */
-
-/*
- * ao_beep.c
- */
-
-/*
- * Various pre-defined beep frequencies
- *
- * frequency = 1/2 (24e6/32) / beep
- */
-
-#define AO_BEEP_LOW 150 /* 2500Hz */
-#define AO_BEEP_MID 94 /* 3989Hz */
-#define AO_BEEP_HIGH 75 /* 5000Hz */
-#define AO_BEEP_OFF 0 /* off */
-
-#define AO_BEEP_g 240 /* 1562.5Hz */
-#define AO_BEEP_gs 227 /* 1652Hz (1655Hz) */
-#define AO_BEEP_aa 214 /* 1752Hz (1754Hz) */
-#define AO_BEEP_bbf 202 /* 1856Hz (1858Hz) */
-#define AO_BEEP_bb 190 /* 1974Hz (1969Hz) */
-#define AO_BEEP_cc 180 /* 2083Hz (2086Hz) */
-#define AO_BEEP_ccs 170 /* 2205Hz (2210Hz) */
-#define AO_BEEP_dd 160 /* 2344Hz (2341Hz) */
-#define AO_BEEP_eef 151 /* 2483Hz (2480Hz) */
-#define AO_BEEP_ee 143 /* 2622Hz (2628Hz) */
-#define AO_BEEP_ff 135 /* 2778Hz (2784Hz) */
-#define AO_BEEP_ffs 127 /* 2953Hz (2950Hz) */
-#define AO_BEEP_gg 120 /* 3125Hz */
-#define AO_BEEP_ggs 113 /* 3319Hz (3311Hz) */
-#define AO_BEEP_aaa 107 /* 3504Hz (3508Hz) */
-#define AO_BEEP_bbbf 101 /* 3713Hz (3716Hz) */
-#define AO_BEEP_bbb 95 /* 3947Hz (3937Hz) */
-#define AO_BEEP_ccc 90 /* 4167Hz (4171Hz) */
-#define AO_BEEP_cccs 85 /* 4412Hz (4419Hz) */
-#define AO_BEEP_ddd 80 /* 4688Hz (4682Hz) */
-#define AO_BEEP_eeef 76 /* 4934Hz (4961Hz) */
-#define AO_BEEP_eee 71 /* 5282Hz (5256Hz) */
-#define AO_BEEP_fff 67 /* 5597Hz (5568Hz) */
-#define AO_BEEP_fffs 64 /* 5859Hz (5899Hz) */
-#define AO_BEEP_ggg 60 /* 6250Hz */
-
-/* Set the beeper to the specified tone */
-void
-ao_beep(uint8_t beep);
-
-/* Turn on the beeper for the specified time */
-void
-ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant;
-
-/* Initialize the beeper */
-void
-ao_beep_init(void);
-
-/*
- * ao_led.c
- */
-
-#define AO_LED_NONE 0
-
-/* Turn on the specified LEDs */
-void
-ao_led_on(uint8_t colors);
-
-/* Turn off the specified LEDs */
-void
-ao_led_off(uint8_t colors);
-
-/* Set all of the LEDs to the specified state */
-void
-ao_led_set(uint8_t colors);
-
-/* Toggle the specified LEDs */
-void
-ao_led_toggle(uint8_t colors);
-
-/* Turn on the specified LEDs for the indicated interval */
-void
-ao_led_for(uint8_t colors, uint16_t ticks) __reentrant;
-
-/* Initialize the LEDs */
-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
- */
-
-/* Put one character to the USB output queue */
-void
-ao_usb_putchar(char c);
-
-/* Get one character from the USB input queue */
-char
-ao_usb_getchar(void);
-
-/* Poll for a charcter on the USB input queue.
- * returns AO_READ_AGAIN if none are available
- */
-char
-ao_usb_pollchar(void);
-
-/* Flush the USB output queue */
-void
-ao_usb_flush(void);
-
-#if HAS_USB
-/* USB interrupt handler */
-void
-ao_usb_isr(void) __interrupt 6;
-#endif
-
-/* Enable the USB controller */
-void
-ao_usb_enable(void);
-
-/* Disable the USB controller */
-void
-ao_usb_disable(void);
-
-/* Initialize the USB system */
-void
-ao_usb_init(void);
-
-/*
- * ao_cmd.c
- */
-
-enum ao_cmd_status {
- ao_cmd_success = 0,
- ao_cmd_lex_error = 1,
- ao_cmd_syntax_error = 2,
-};
-
-extern __pdata uint16_t ao_cmd_lex_i;
-extern __pdata uint32_t ao_cmd_lex_u32;
-extern __pdata char ao_cmd_lex_c;
-extern __pdata enum ao_cmd_status ao_cmd_status;
-
-void
-ao_cmd_lex(void);
-
-void
-ao_cmd_put8(uint8_t v);
-
-void
-ao_cmd_put16(uint16_t v);
-
-void
-ao_cmd_white(void);
-
-void
-ao_cmd_hex(void);
-
-void
-ao_cmd_decimal(void);
-
-uint8_t
-ao_match_word(__code char *word);
-
-struct ao_cmds {
- void (*func)(void);
- __code char *help;
-};
-
-void
-ao_cmd_register(__code struct ao_cmds *cmds);
-
-void
-ao_cmd_init(void);
-
-#if HAS_CMD_FILTER
-/*
- * Provided by an external module to filter raw command lines
- */
-uint8_t
-ao_cmd_filter(void);
-#endif
-
-/*
- * ao_dma.c
- */
-
-/* Allocate a DMA channel. the 'done' parameter will be set when the
- * dma is finished and will be used to wakeup any waiters
- */
-
-uint8_t
-ao_dma_alloc(__xdata uint8_t * done);
-
-/* Setup a DMA channel */
-void
-ao_dma_set_transfer(uint8_t id,
- void __xdata *srcaddr,
- void __xdata *dstaddr,
- uint16_t count,
- uint8_t cfg0,
- uint8_t cfg1);
-
-/* Start a DMA channel */
-void
-ao_dma_start(uint8_t id);
-
-/* Manually trigger a DMA channel */
-void
-ao_dma_trigger(uint8_t id);
-
-/* Abort a running DMA transfer */
-void
-ao_dma_abort(uint8_t id);
-
-/* DMA interrupt routine */
-void
-ao_dma_isr(void) __interrupt 8;
-
-/*
- * ao_mutex.c
- */
-
-void
-ao_mutex_get(__xdata uint8_t *ao_mutex) __reentrant;
-
-void
-ao_mutex_put(__xdata uint8_t *ao_mutex) __reentrant;
-
-/*
- * Storage interface, provided by one of the eeprom or flash
- * drivers
- */
-
-/* Total bytes of available storage */
-extern __pdata uint32_t ao_storage_total;
-
-/* Block size - device is erased in these units. At least 256 bytes */
-extern __pdata uint32_t ao_storage_block;
-
-/* Byte offset of config block. Will be ao_storage_block bytes long */
-extern __pdata uint32_t ao_storage_config;
-
-/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */
-extern __pdata uint16_t ao_storage_unit;
-
-#define AO_STORAGE_ERASE_LOG (ao_storage_config + AO_CONFIG_MAX_SIZE)
-
-/* Initialize above values. Can only be called once the OS is running */
-void
-ao_storage_setup(void) __reentrant;
-
-/* Write data. Returns 0 on failure, 1 on success */
-uint8_t
-ao_storage_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant;
-
-/* Read data. Returns 0 on failure, 1 on success */
-uint8_t
-ao_storage_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant;
-
-/* Erase a block of storage. This always clears ao_storage_block bytes */
-uint8_t
-ao_storage_erase(uint32_t pos) __reentrant;
-
-/* Flush any pending writes to stable storage */
-void
-ao_storage_flush(void) __reentrant;
-
-/* Initialize the storage code */
-void
-ao_storage_init(void);
-
-/*
- * Low-level functions wrapped by ao_storage.c
- */
-
-/* Read data within a storage unit */
-uint8_t
-ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant;
-
-/* Write data within a storage unit */
-uint8_t
-ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant;
-
-/* Initialize low-level device bits */
-void
-ao_storage_device_init(void);
-
-/* Print out information about flash chips */
-void
-ao_storage_device_info(void) __reentrant;
-
-/*
- * ao_log.c
- */
-
-/* We record flight numbers in the first record of
- * the log. Tasks may wait for this to be initialized
- * by sleeping on this variable.
- */
-extern __xdata uint16_t ao_flight_number;
-
-extern __pdata uint32_t ao_log_current_pos;
-extern __pdata uint32_t ao_log_end_pos;
-extern __pdata uint32_t ao_log_start_pos;
-extern __xdata uint8_t ao_log_running;
-extern __pdata enum flight_state ao_log_state;
-
-/* required functions from the underlying log system */
-
-#define AO_LOG_FORMAT_UNKNOWN 0 /* unknown; altosui will have to guess */
-#define AO_LOG_FORMAT_FULL 1 /* 8 byte typed log records */
-#define AO_LOG_FORMAT_TINY 2 /* two byte state/baro records */
-#define AO_LOG_FORMAT_TELEMETRY 3 /* 32 byte ao_telemetry records */
-#define AO_LOG_FORMAT_TELESCIENCE 4 /* 32 byte typed telescience records */
-#define AO_LOG_FORMAT_NONE 127 /* No log at all */
-
-extern __code uint8_t ao_log_format;
-
-/* Return the flight number from the given log slot, 0 if none */
-uint16_t
-ao_log_flight(uint8_t slot);
-
-/* Flush the log */
-void
-ao_log_flush(void);
-
-/* Logging thread main routine */
-void
-ao_log(void);
-
-/* functions provided in ao_log.c */
-
-/* Figure out the current flight number */
-void
-ao_log_scan(void) __reentrant;
-
-/* Return the position of the start of the given log slot */
-uint32_t
-ao_log_pos(uint8_t slot);
-
-/* Start logging to eeprom */
-void
-ao_log_start(void);
-
-/* Stop logging */
-void
-ao_log_stop(void);
-
-/* Initialize the logging system */
-void
-ao_log_init(void);
-
-/* Write out the current flight number to the erase log */
-void
-ao_log_write_erase(uint8_t pos);
-
-/* Returns true if there are any logs stored in eeprom */
-uint8_t
-ao_log_present(void);
-
-/* Returns true if there is no more storage space available */
-uint8_t
-ao_log_full(void);
-
-/*
- * ao_log_big.c
- */
-
-/*
- * The data log is recorded in the eeprom as a sequence
- * of data packets.
- *
- * Each packet starts with a 4-byte header that has the
- * packet type, the packet checksum and the tick count. Then
- * they all contain 2 16 bit values which hold packet-specific
- * data.
- *
- * For each flight, the first packet
- * is FLIGHT packet, indicating the serial number of the
- * device and a unique number marking the number of flights
- * recorded by this device.
- *
- * During flight, data from the accelerometer and barometer
- * are recorded in SENSOR packets, using the raw 16-bit values
- * read from the A/D converter.
- *
- * Also during flight, but at a lower rate, the deployment
- * sensors are recorded in DEPLOY packets. The goal here is to
- * detect failure in the deployment circuits.
- *
- * STATE packets hold state transitions as the flight computer
- * transitions through different stages of the flight.
- */
-#define AO_LOG_FLIGHT 'F'
-#define AO_LOG_SENSOR 'A'
-#define AO_LOG_TEMP_VOLT 'T'
-#define AO_LOG_DEPLOY 'D'
-#define AO_LOG_STATE 'S'
-#define AO_LOG_GPS_TIME 'G'
-#define AO_LOG_GPS_LAT 'N'
-#define AO_LOG_GPS_LON 'W'
-#define AO_LOG_GPS_ALT 'H'
-#define AO_LOG_GPS_SAT 'V'
-#define AO_LOG_GPS_DATE 'Y'
-
-#define AO_LOG_POS_NONE (~0UL)
-
-struct ao_log_record {
- char type;
- uint8_t csum;
- uint16_t tick;
- union {
- struct {
- int16_t ground_accel;
- uint16_t flight;
- } flight;
- struct {
- int16_t accel;
- int16_t pres;
- } sensor;
- struct {
- int16_t temp;
- int16_t v_batt;
- } temp_volt;
- struct {
- int16_t drogue;
- int16_t main;
- } deploy;
- struct {
- uint16_t state;
- uint16_t reason;
- } state;
- struct {
- uint8_t hour;
- uint8_t minute;
- uint8_t second;
- uint8_t flags;
- } gps_time;
- int32_t gps_latitude;
- int32_t gps_longitude;
- struct {
- int16_t altitude;
- uint16_t unused;
- } gps_altitude;
- struct {
- uint16_t svid;
- uint8_t unused;
- uint8_t c_n;
- } gps_sat;
- struct {
- uint8_t year;
- uint8_t month;
- uint8_t day;
- uint8_t extra;
- } gps_date;
- struct {
- uint16_t d0;
- uint16_t d1;
- } anon;
- } u;
-};
-
-/* Write a record to the eeprom log */
-uint8_t
-ao_log_data(__xdata struct ao_log_record *log) __reentrant;
-
-/*
- * ao_flight.c
- */
-
-enum ao_flight_state {
- ao_flight_startup = 0,
- ao_flight_idle = 1,
- ao_flight_pad = 2,
- ao_flight_boost = 3,
- ao_flight_fast = 4,
- ao_flight_coast = 5,
- ao_flight_drogue = 6,
- ao_flight_main = 7,
- ao_flight_landed = 8,
- ao_flight_invalid = 9
-};
-
-extern __pdata enum ao_flight_state ao_flight_state;
-
-extern __pdata uint16_t ao_launch_time;
-extern __pdata uint8_t ao_flight_force_idle;
-
-/* Flight thread */
-void
-ao_flight(void);
-
-/* Initialize flight thread */
-void
-ao_flight_init(void);
-
-/*
- * ao_flight_nano.c
- */
-
-void
-ao_flight_nano_init(void);
-
-/*
- * ao_sample.c
- */
-
-/*
- * Barometer calibration
- *
- * We directly sample the barometer. The specs say:
- *
- * Pressure range: 15-115 kPa
- * Voltage at 115kPa: 2.82
- * Output scale: 27mV/kPa
- *
- * If we want to detect launch with the barometer, we need
- * a large enough bump to not be fooled by noise. At typical
- * launch elevations (0-2000m), a 200Pa pressure change cooresponds
- * to about a 20m elevation change. This is 5.4mV, or about 3LSB.
- * As all of our calculations are done in 16 bits, we'll actually see a change
- * of 16 times this though
- *
- * 27 mV/kPa * 32767 / 3300 counts/mV = 268.1 counts/kPa
- */
-
-/* Accelerometer calibration
- *
- * We're sampling the accelerometer through a resistor divider which
- * consists of 5k and 10k resistors. This multiplies the values by 2/3.
- * That goes into the cc1111 A/D converter, which is running at 11 bits
- * of precision with the bits in the MSB of the 16 bit value. Only positive
- * values are used, so values should range from 0-32752 for 0-3.3V. The
- * specs say we should see 40mV/g (uncalibrated), multiply by 2/3 for what
- * the A/D converter sees (26.67 mV/g). We should see 32752/3300 counts/mV,
- * for a final computation of:
- *
- * 26.67 mV/g * 32767/3300 counts/mV = 264.8 counts/g
- *
- * Zero g was measured at 16000 (we would expect 16384).
- * Note that this value is only require to tell if the
- * rocket is standing upright. Once that is determined,
- * the value of the accelerometer is averaged for 100 samples
- * to find the resting accelerometer value, which is used
- * for all further flight computations
- */
-
-#define GRAVITY 9.80665
-
-/*
- * Above this height, the baro sensor doesn't work
- */
-#define AO_MAX_BARO_HEIGHT 12000
-
-/*
- * Above this speed, baro measurements are unreliable
- */
-#define AO_MAX_BARO_SPEED 200
-
-#define ACCEL_NOSE_UP (ao_accel_2g >> 2)
-
-/*
- * Speed and acceleration are scaled by 16 to provide a bit more
- * resolution while still having reasonable range. Note that this
- * limits speed to 2047m/s (around mach 6) and acceleration to
- * 2047m/s² (over 200g)
- */
-
-#define AO_M_TO_HEIGHT(m) ((int16_t) (m))
-#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16))
-#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16))
-
-extern __pdata uint16_t ao_sample_tick; /* time of last data */
-extern __pdata int16_t ao_sample_pres; /* most recent pressure sensor reading */
-extern __pdata int16_t ao_sample_alt; /* MSL of ao_sample_pres */
-extern __pdata int16_t ao_sample_height; /* AGL of ao_sample_pres */
-extern __data uint8_t ao_sample_adc; /* Ring position of last processed sample */
-
-#if HAS_ACCEL
-extern __pdata int16_t ao_sample_accel; /* most recent accel sensor reading */
-#endif
-
-extern __pdata int16_t ao_ground_pres; /* startup pressure */
-extern __pdata int16_t ao_ground_height; /* MSL of ao_ground_pres */
-
-#if HAS_ACCEL
-extern __pdata int16_t ao_ground_accel; /* startup acceleration */
-extern __pdata int16_t ao_accel_2g; /* factory accel calibration */
-extern __pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */
-#endif
-
-void ao_sample_init(void);
-
-/* returns FALSE in preflight mode, TRUE in flight mode */
-uint8_t ao_sample(void);
-
-/*
- * ao_kalman.c
- */
-
-#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5))
-#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5))
-#define from_fix(x) ((x) >> 16)
-
-extern __pdata int16_t ao_height; /* meters */
-extern __pdata int16_t ao_speed; /* m/s * 16 */
-extern __pdata int16_t ao_accel; /* m/s² * 16 */
-extern __pdata int16_t ao_max_height; /* max of ao_height */
-extern __pdata int16_t ao_avg_height; /* running average of height */
-
-extern __pdata int16_t ao_error_h;
-extern __pdata int16_t ao_error_h_sq_avg;
-
-#if HAS_ACCEL
-extern __pdata int16_t ao_error_a;
-#endif
-
-void ao_kalman(void);
-
-/*
- * ao_report.c
- */
-
-void
-ao_report_init(void);
-
-/*
- * ao_convert.c
- *
- * Given raw data, convert to SI units
- */
-
-/* pressure from the sensor to altitude in meters */
-int16_t
-ao_pres_to_altitude(int16_t pres) __reentrant;
-
-int16_t
-ao_altitude_to_pres(int16_t alt) __reentrant;
-
-int16_t
-ao_temp_to_dC(int16_t temp) __reentrant;
-
-/*
- * ao_dbg.c
- *
- * debug another telemetrum board
- */
-
-/* Send a byte to the dbg target */
-void
-ao_dbg_send_byte(uint8_t byte);
-
-/* Receive a byte from the dbg target */
-uint8_t
-ao_dbg_recv_byte(void);
-
-/* Start a bulk transfer to/from dbg target memory */
-void
-ao_dbg_start_transfer(uint16_t addr);
-
-/* End a bulk transfer to/from dbg target memory */
-void
-ao_dbg_end_transfer(void);
-
-/* Write a byte to dbg target memory */
-void
-ao_dbg_write_byte(uint8_t byte);
-
-/* Read a byte from dbg target memory */
-uint8_t
-ao_dbg_read_byte(void);
-
-/* Enable dbg mode, switching use of the pins */
-void
-ao_dbg_debug_mode(void);
-
-/* Reset the dbg target */
-void
-ao_dbg_reset(void);
-
-void
-ao_dbg_init(void);
-
-/*
- * ao_serial.c
- */
-
-#ifndef HAS_SERIAL_1
-#error Please define HAS_SERIAL_1
-#endif
-
-#if HAS_SERIAL_1
-#ifndef USE_SERIAL_STDIN
-#error Please define USE_SERIAL_STDIN
-#endif
-
-void
-ao_serial_rx1_isr(void) __interrupt 3;
-
-void
-ao_serial_tx1_isr(void) __interrupt 14;
-
-char
-ao_serial_getchar(void) __critical;
-
-#if USE_SERIAL_STDIN
-char
-ao_serial_pollchar(void) __critical;
-
-void
-ao_serial_set_stdin(uint8_t stdin);
-#endif
-
-void
-ao_serial_putchar(char c) __critical;
-
-void
-ao_serial_drain(void) __critical;
-
-#define AO_SERIAL_SPEED_4800 0
-#define AO_SERIAL_SPEED_9600 1
-#define AO_SERIAL_SPEED_19200 2
-#define AO_SERIAL_SPEED_57600 3
-
-void
-ao_serial_set_speed(uint8_t speed);
-
-void
-ao_serial_init(void);
-#endif
-
-/*
- * ao_spi.c
- */
-
-extern __xdata uint8_t ao_spi_mutex;
-
-#define ao_spi_get_mask(reg,mask) do {\
- ao_mutex_get(&ao_spi_mutex); \
- (reg) &= ~(mask); \
- } while (0)
-
-#define ao_spi_put_mask(reg,mask) do { \
- (reg) |= (mask); \
- ao_mutex_put(&ao_spi_mutex); \
- } while (0)
-
-#define ao_spi_get_bit(bit) do {\
- ao_mutex_get(&ao_spi_mutex); \
- (bit) = 0; \
- } while (0)
-
-#define ao_spi_put_bit(bit) do { \
- (bit) = 1; \
- ao_mutex_put(&ao_spi_mutex); \
- } while (0)
-
-/*
- * The SPI mutex must be held to call either of these
- * functions -- this mutex covers the entire SPI operation,
- * from chip select low to chip select high
- */
-
-void
-ao_spi_send(void __xdata *block, uint16_t len) __reentrant;
-
-void
-ao_spi_recv(void __xdata *block, uint16_t len) __reentrant;
-
-void
-ao_spi_init(void);
-
-/*
- * ao_telemetry.c
- */
-#define AO_MAX_CALLSIGN 8
-#define AO_MAX_VERSION 8
-#define AO_MAX_TELEMETRY 128
-
-struct ao_telemetry_generic {
- uint16_t serial; /* 0 */
- uint16_t tick; /* 2 */
- uint8_t type; /* 4 */
- uint8_t payload[27]; /* 5 */
- /* 32 */
-};
-
-#define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01
-#define AO_TELEMETRY_SENSOR_TELEMINI 0x02
-#define AO_TELEMETRY_SENSOR_TELENANO 0x03
-
-struct ao_telemetry_sensor {
- uint16_t serial; /* 0 */
- uint16_t tick; /* 2 */
- uint8_t type; /* 4 */
-
- uint8_t state; /* 5 flight state */
- int16_t accel; /* 6 accelerometer (TM only) */
- int16_t pres; /* 8 pressure sensor */
- int16_t temp; /* 10 temperature sensor */
- int16_t v_batt; /* 12 battery voltage */
- int16_t sense_d; /* 14 drogue continuity sense (TM/Tm) */
- int16_t sense_m; /* 16 main continuity sense (TM/Tm) */
-
- int16_t acceleration; /* 18 m/s² * 16 */
- int16_t speed; /* 20 m/s * 16 */
- int16_t height; /* 22 m */
-
- int16_t ground_pres; /* 24 average pres on pad */
- int16_t ground_accel; /* 26 average accel on pad */
- int16_t accel_plus_g; /* 28 accel calibration at +1g */
- int16_t accel_minus_g; /* 30 accel calibration at -1g */
- /* 32 */
-};
-
-#define AO_TELEMETRY_CONFIGURATION 0x04
-
-struct ao_telemetry_configuration {
- uint16_t serial; /* 0 */
- uint16_t tick; /* 2 */
- uint8_t type; /* 4 */
-
- uint8_t device; /* 5 device type */
- uint16_t flight; /* 6 flight number */
- uint8_t config_major; /* 8 Config major version */
- uint8_t config_minor; /* 9 Config minor version */
- uint16_t apogee_delay; /* 10 Apogee deploy delay in seconds */
- uint16_t main_deploy; /* 12 Main deploy alt in meters */
- uint16_t flight_log_max; /* 14 Maximum flight log size in kB */
- char callsign[AO_MAX_CALLSIGN]; /* 16 Radio operator identity */
- char version[AO_MAX_VERSION]; /* 24 Software version */
- /* 32 */
-};
-
-#define AO_TELEMETRY_LOCATION 0x05
-
-#define AO_GPS_MODE_NOT_VALID 'N'
-#define AO_GPS_MODE_AUTONOMOUS 'A'
-#define AO_GPS_MODE_DIFFERENTIAL 'D'
-#define AO_GPS_MODE_ESTIMATED 'E'
-#define AO_GPS_MODE_MANUAL 'M'
-#define AO_GPS_MODE_SIMULATED 'S'
-
-struct ao_telemetry_location {
- uint16_t serial; /* 0 */
- uint16_t tick; /* 2 */
- uint8_t type; /* 4 */
-
- uint8_t flags; /* 5 Number of sats and other flags */
- int16_t altitude; /* 6 GPS reported altitude (m) */
- int32_t latitude; /* 8 latitude (degrees * 10⁷) */
- int32_t longitude; /* 12 longitude (degrees * 10⁷) */
- uint8_t year; /* 16 (- 2000) */
- uint8_t month; /* 17 (1-12) */
- uint8_t day; /* 18 (1-31) */
- uint8_t hour; /* 19 (0-23) */
- uint8_t minute; /* 20 (0-59) */
- uint8_t second; /* 21 (0-59) */
- uint8_t pdop; /* 22 (m * 5) */
- uint8_t hdop; /* 23 (m * 5) */
- uint8_t vdop; /* 24 (m * 5) */
- uint8_t mode; /* 25 */
- uint16_t ground_speed; /* 26 cm/s */
- int16_t climb_rate; /* 28 cm/s */
- uint8_t course; /* 30 degrees / 2 */
- uint8_t unused[1]; /* 31 */
- /* 32 */
-};
-
-#define AO_TELEMETRY_SATELLITE 0x06
-
-struct ao_telemetry_satellite_info {
- uint8_t svid;
- uint8_t c_n_1;
-};
-
-struct ao_telemetry_satellite {
- uint16_t serial; /* 0 */
- uint16_t tick; /* 2 */
- uint8_t type; /* 4 */
- uint8_t channels; /* 5 number of reported sats */
-
- struct ao_telemetry_satellite_info sats[12]; /* 6 */
- uint8_t unused[2]; /* 30 */
- /* 32 */
-};
-
-#define AO_TELEMETRY_COMPANION 0x07
-
-#define AO_COMPANION_MAX_CHANNELS 12
-
-struct ao_telemetry_companion {
- uint16_t serial; /* 0 */
- uint16_t tick; /* 2 */
- uint8_t type; /* 4 */
- uint8_t board_id; /* 5 */
-
- uint8_t update_period; /* 6 */
- uint8_t channels; /* 7 */
- uint16_t companion_data[AO_COMPANION_MAX_CHANNELS]; /* 8 */
- /* 32 */
-};
-
-union ao_telemetry_all {
- struct ao_telemetry_generic generic;
- struct ao_telemetry_sensor sensor;
- struct ao_telemetry_configuration configuration;
- struct ao_telemetry_location location;
- struct ao_telemetry_satellite satellite;
- struct ao_telemetry_companion companion;
-};
-
-/*
- * ao_gps.c
- */
-
-#define AO_GPS_NUM_SAT_MASK (0xf << 0)
-#define AO_GPS_NUM_SAT_SHIFT (0)
-
-#define AO_GPS_VALID (1 << 4)
-#define AO_GPS_RUNNING (1 << 5)
-#define AO_GPS_DATE_VALID (1 << 6)
-#define AO_GPS_COURSE_VALID (1 << 7)
-
-extern __pdata uint16_t ao_gps_tick;
-extern __xdata uint8_t ao_gps_mutex;
-extern __xdata struct ao_telemetry_location ao_gps_data;
-extern __xdata struct ao_telemetry_satellite ao_gps_tracking_data;
-
-struct ao_gps_orig {
- uint8_t year;
- uint8_t month;
- uint8_t day;
- uint8_t hour;
- uint8_t minute;
- uint8_t second;
- uint8_t flags;
- int32_t latitude; /* degrees * 10⁷ */
- int32_t longitude; /* degrees * 10⁷ */
- int16_t altitude; /* m */
- uint16_t ground_speed; /* cm/s */
- uint8_t course; /* degrees / 2 */
- uint8_t hdop; /* * 5 */
- int16_t climb_rate; /* cm/s */
- uint16_t h_error; /* m */
- uint16_t v_error; /* m */
-};
-
-struct ao_gps_sat_orig {
- uint8_t svid;
- uint8_t c_n_1;
-};
-
-#define AO_MAX_GPS_TRACKING 12
-
-struct ao_gps_tracking_orig {
- uint8_t channels;
- struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING];
-};
-
-void
-ao_gps(void);
-
-void
-ao_gps_print(__xdata struct ao_gps_orig *gps_data);
-
-void
-ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data);
-
-void
-ao_gps_init(void);
-
-/*
- * ao_gps_report.c
- */
-
-void
-ao_gps_report(void);
-
-void
-ao_gps_report_init(void);
-
-/*
- * ao_telemetry_orig.c
- */
-
-struct ao_telemetry_orig {
- uint16_t serial;
- uint16_t flight;
- uint8_t flight_state;
- int16_t accel;
- int16_t ground_accel;
- union {
- struct {
- int16_t speed;
- int16_t unused;
- } k;
- int32_t flight_vel;
- } u;
- int16_t height;
- int16_t ground_pres;
- int16_t accel_plus_g;
- int16_t accel_minus_g;
- struct ao_adc adc;
- struct ao_gps_orig gps;
- char callsign[AO_MAX_CALLSIGN];
- struct ao_gps_tracking_orig gps_tracking;
-};
-
-struct ao_telemetry_tiny {
- uint16_t serial;
- uint16_t flight;
- uint8_t flight_state;
- int16_t height; /* AGL in meters */
- int16_t speed; /* in m/s * 16 */
- int16_t accel; /* in m/s² * 16 */
- int16_t ground_pres; /* sensor units */
- struct ao_adc adc; /* raw ADC readings */
- 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;
- uint8_t status;
-};
-
-struct ao_telemetry_tiny_recv {
- struct ao_telemetry_tiny telemetry_tiny;
- int8_t rssi;
- uint8_t status;
-};
-
-/* Set delay between telemetry reports (0 to disable) */
-
-#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)
-
-void
-ao_telemetry_set_interval(uint16_t interval);
-
-void
-ao_rdf_set(uint8_t rdf);
-
-void
-ao_telemetry_init(void);
-
-void
-ao_telemetry_orig_init(void);
-
-void
-ao_telemetry_tiny_init(void);
-
-/*
- * ao_radio.c
- */
-
-extern __xdata uint8_t ao_radio_dma;
-extern __xdata uint8_t ao_radio_dma_done;
-extern __xdata uint8_t ao_radio_done;
-extern __xdata uint8_t ao_radio_mutex;
-
-void
-ao_radio_general_isr(void) __interrupt 16;
-
-void
-ao_radio_get(uint8_t len);
-
-#define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
-
-void
-ao_radio_set_packet(void);
-
-void
-ao_radio_send(__xdata void *data, uint8_t size) __reentrant;
-
-uint8_t
-ao_radio_recv(__xdata void *data, uint8_t size) __reentrant;
-
-void
-ao_radio_recv_abort(void);
-
-void
-ao_radio_rdf(int ms);
-
-void
-ao_radio_rdf_abort(void);
-
-void
-ao_radio_idle(void);
-
-void
-ao_radio_init(void);
-
-/*
- * ao_monitor.c
- */
-
-extern const char const * const ao_state_names[];
-
-void
-ao_monitor(void);
-
-#define AO_MONITORING_OFF 0
-#define AO_MONITORING_ORIG 1
-#define AO_MONITORING_TINY 2
-
-void
-ao_set_monitor(uint8_t monitoring);
-
-void
-ao_monitor_init(uint8_t led, uint8_t monitoring) __reentrant;
-
-/*
- * ao_stdio.c
- */
-
-#define AO_READ_AGAIN ((char) -1)
-
-struct ao_stdio {
- char (*pollchar)(void);
- void (*putchar)(char c) __reentrant;
- void (*flush)(void);
- uint8_t echo;
-};
-
-extern __xdata struct ao_stdio ao_stdios[];
-extern __pdata int8_t ao_cur_stdio;
-extern __pdata int8_t ao_num_stdios;
-
-void
-flush(void);
-
-extern __xdata uint8_t ao_stdin_ready;
-
-uint8_t
-ao_echo(void);
-
-int8_t
-ao_add_stdio(char (*pollchar)(void),
- void (*putchar)(char) __reentrant,
- void (*flush)(void)) __reentrant;
-
-/*
- * ao_ignite.c
- */
-
-enum ao_igniter {
- ao_igniter_drogue = 0,
- ao_igniter_main = 1
-};
-
-void
-ao_ignite(enum ao_igniter igniter);
-
-enum ao_igniter_status {
- ao_igniter_unknown, /* unknown status (ambiguous voltage) */
- ao_igniter_ready, /* continuity detected */
- ao_igniter_active, /* igniter firing */
- ao_igniter_open, /* open circuit detected */
-};
-
-enum ao_igniter_status
-ao_igniter_status(enum ao_igniter igniter);
-
-void
-ao_ignite_set_pins(void);
-
-void
-ao_igniter_init(void);
-
-/*
- * ao_config.c
- */
-
-#define AO_CONFIG_MAJOR 1
-#define AO_CONFIG_MINOR 8
-
-struct ao_config {
- uint8_t major;
- uint8_t minor;
- uint16_t main_deploy;
- int16_t accel_plus_g; /* changed for minor version 2 */
- uint8_t radio_channel;
- char callsign[AO_MAX_CALLSIGN + 1];
- uint8_t apogee_delay; /* minor version 1 */
- int16_t accel_minus_g; /* minor version 2 */
- uint32_t radio_cal; /* minor version 3 */
- uint32_t flight_log_max; /* minor version 4 */
- uint8_t ignite_mode; /* minor version 5 */
- uint8_t pad_orientation; /* minor version 6 */
- uint32_t radio_setting; /* minor version 7 */
- uint8_t radio_enable; /* minor version 8 */
-};
-
-#define AO_IGNITE_MODE_DUAL 0
-#define AO_IGNITE_MODE_APOGEE 1
-#define AO_IGNITE_MODE_MAIN 2
-
-#define AO_PAD_ORIENTATION_ANTENNA_UP 0
-#define AO_PAD_ORIENTATION_ANTENNA_DOWN 1
-
-extern __xdata struct ao_config ao_config;
-
-#define AO_CONFIG_MAX_SIZE 128
-
-void
-ao_config_get(void);
-
-void
-ao_config_put(void);
-
-void
-ao_config_init(void);
-
-/*
- * ao_rssi.c
- */
-
-void
-ao_rssi_set(int rssi_value);
-
-void
-ao_rssi_init(uint8_t rssi_led);
-
-/*
- * ao_product.c
- *
- * values which need to be defined for
- * each instance of a product
- */
-
-extern const char ao_version[];
-extern const char ao_manufacturer[];
-extern const char ao_product[];
-
-/*
- * Fifos
- */
-
-#define AO_FIFO_SIZE 32
-
-struct ao_fifo {
- uint8_t insert;
- uint8_t remove;
- char fifo[AO_FIFO_SIZE];
-};
-
-#define ao_fifo_insert(f,c) do { \
- (f).fifo[(f).insert] = (c); \
- (f).insert = ((f).insert + 1) & (AO_FIFO_SIZE-1); \
-} while(0)
-
-#define ao_fifo_remove(f,c) do {\
- c = (f).fifo[(f).remove]; \
- (f).remove = ((f).remove + 1) & (AO_FIFO_SIZE-1); \
-} while(0)
-
-#define ao_fifo_full(f) ((((f).insert + 1) & (AO_FIFO_SIZE-1)) == (f).remove)
-#define ao_fifo_empty(f) ((f).insert == (f).remove)
-
-/*
- * ao_packet.c
- *
- * Packet-based command interface
- */
-
-#define AO_PACKET_MAX 64
-#define AO_PACKET_SYN (uint8_t) 0xff
-
-struct ao_packet {
- uint8_t addr;
- uint8_t len;
- uint8_t seq;
- uint8_t ack;
- uint8_t d[AO_PACKET_MAX];
- uint8_t callsign[AO_MAX_CALLSIGN];
-};
-
-struct ao_packet_recv {
- struct ao_packet packet;
- int8_t rssi;
- uint8_t status;
-};
-
-extern __xdata struct ao_packet_recv ao_rx_packet;
-extern __xdata struct ao_packet ao_tx_packet;
-extern __xdata struct ao_task ao_packet_task;
-extern __xdata uint8_t ao_packet_enable;
-extern __xdata uint8_t ao_packet_master_sleeping;
-extern __pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used;
-
-void
-ao_packet_send(void);
-
-uint8_t
-ao_packet_recv(void);
-
-void
-ao_packet_flush(void);
-
-void
-ao_packet_putchar(char c) __reentrant;
-
-char
-ao_packet_pollchar(void) __critical;
-
-/* ao_packet_master.c */
-
-void
-ao_packet_master_init(void);
-
-/* ao_packet_slave.c */
-
-void
-ao_packet_slave_start(void);
-
-void
-ao_packet_slave_stop(void);
-
-void
-ao_packet_slave_init(uint8_t enable);
-
-/* ao_btm.c */
-
-/* If bt_link is on P2, this interrupt is shared by USB, so the USB
- * code calls this function. Otherwise, it's a regular ISR.
- */
-
-void
-ao_btm_isr(void)
-#if BT_LINK_ON_P1
- __interrupt 15
-#endif
- ;
-
-void
-ao_btm_init(void);
-
-/* ao_companion.c */
-
-#define AO_COMPANION_SETUP 1
-#define AO_COMPANION_FETCH 2
-#define AO_COMPANION_NOTIFY 3
-
-struct ao_companion_command {
- uint8_t command;
- uint8_t flight_state;
- uint16_t tick;
- uint16_t serial;
- uint16_t flight;
-};
-
-struct ao_companion_setup {
- uint16_t board_id;
- uint16_t board_id_inverse;
- uint8_t update_period;
- uint8_t channels;
-};
-
-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 uint16_t ao_companion_data[AO_COMPANION_MAX_CHANNELS];
-
-void
-ao_companion_init(void);
-
-#endif /* _AO_H_ */
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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_pins.h"
-
-volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING];
-#if HAS_ACCEL_REF
-volatile __xdata uint16_t ao_accel_ref[AO_ADC_RING];
-#endif
-volatile __data uint8_t ao_adc_head;
-
-void
-ao_adc_poll(void)
-{
-#if HAS_ACCEL_REF
- ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 2;
-#else
-# ifdef TELENANO_V_0_1
- ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 1;
-# else
- ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 0;
-# endif
-#endif
-}
-
-void
-ao_adc_get(__xdata struct ao_adc *packet)
-{
- uint8_t i = ao_adc_ring_prev(ao_sample_adc);
- memcpy(packet, &ao_adc_ring[i], sizeof (struct ao_adc));
-}
-
-void
-ao_adc_isr(void) __interrupt 1
-{
- uint8_t sequence;
- uint8_t __xdata *a;
-
- sequence = (ADCCON2 & ADCCON2_SCH_MASK) >> ADCCON2_SCH_SHIFT;
-#if IGNITE_ON_P2
- /* TeleMetrum readings */
-#if HAS_ACCEL_REF
- if (sequence == 2) {
- a = (uint8_t __xdata *) (&ao_accel_ref[ao_adc_head]);
- sequence = 0;
- } else
-#endif
- {
- if (sequence == ADCCON3_ECH_TEMP)
- sequence = 2;
- a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].accel + sequence);
- sequence++;
- }
-#define GOT_ADC
- a[0] = ADCL;
- a[1] = ADCH;
- if (sequence < 6) {
-#if HAS_EXTERNAL_TEMP == 0
- /* start next channel conversion */
- /* v0.2 replaces external temp sensor with internal one */
- if (sequence == 2)
- ADCCON3 = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP;
- else
-#endif
- ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | sequence;
- }
-#endif
-
-#if IGNITE_ON_P0
- /* TeleMini readings */
- a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].pres);
-#ifdef TELEMINI_V_1_0
- switch (sequence) {
- case 0:
- /* pressure */
- a += 0;
- sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 1;
- break;
- case 1:
- /* drogue sense */
- a += 6;
- sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 2;
- break;
- case 2:
- /* main sense */
- a += 8;
- sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 3;
- break;
- case 3:
- /* battery */
- a += 4;
- sequence = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP;
- break;
- case ADCCON3_ECH_TEMP:
- a += 2;
- sequence = 0;
- break;
- }
-#define GOT_ADC
-#endif
-#ifdef TELENANO_V_0_1
- switch (sequence) {
- case 1:
- /* pressure */
- a += 0;
- sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 3;
- break;
- case 3:
- /* battery */
- a += 4;
- sequence = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP;
- break;
- case ADCCON3_ECH_TEMP:
- a += 2;
- sequence = 0;
- break;
- }
-#define GOT_ADC
-#endif
- a[0] = ADCL;
- a[1] = ADCH;
- if (sequence) {
- /* Start next conversion */
- ADCCON3 = sequence;
- }
-#endif
-#ifndef GOT_ADC
-#error No known ADC configuration set
-#endif
-
- else {
- /* record this conversion series */
- ao_adc_ring[ao_adc_head].tick = ao_time();
- ao_adc_head = ao_adc_ring_next(ao_adc_head);
- ao_wakeup(DATA_TO_XDATA(&ao_adc_head));
- }
-}
-
-static void
-ao_adc_dump(void) __reentrant
-{
- static __xdata struct ao_adc packet;
- ao_adc_get(&packet);
- printf("tick: %5u accel: %5d pres: %5d temp: %5d batt: %5d drogue: %5d main: %5d\n",
- packet.tick, packet.accel, packet.pres, packet.temp,
- packet.v_batt, packet.sense_d, packet.sense_m);
-}
-
-__code struct ao_cmds ao_adc_cmds[] = {
- { ao_adc_dump, "a\0Current ADC" },
- { 0, NULL },
-};
-
-void
-ao_adc_init(void)
-{
-#if IGNITE_ON_P2
- /* TeleMetrum configuration */
- ADCCFG = ((1 << 0) | /* acceleration */
- (1 << 1) | /* pressure */
-#if HAS_EXTERNAL_TEMP
- (1 << 2) | /* v0.1 temperature */
-#endif
- (1 << 3) | /* battery voltage */
- (1 << 4) | /* drogue sense */
- (1 << 5)); /* main sense */
-#endif
-
-#if IGNITE_ON_P0
- /* TeleMini configuration */
- ADCCFG = ((1 << 0) | /* pressure */
- (1 << 1) | /* drogue sense */
- (1 << 2) | /* main sense */
- (1 << 3)); /* battery voltage */
-#endif
-
- /* enable interrupts */
- ADCIF = 0;
- IEN0 |= IEN0_ADCIE;
- ao_cmd_register(&ao_adc_cmds[0]);
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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;
-
-/* Stub for systems which have no ADC */
-void
-ao_adc_poll(void)
-{
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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
-ao_beep(uint8_t beep)
-{
- if (beep == 0) {
- P2_0 = 0;
- P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_GPIO;
- T4CTL = 0;
- } else {
- P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_PERIPHERAL;
- T4CC0 = beep;
- T4CTL = TxCTL_DIV_32 | TxCTL_MODE_MODULO | TxCTL_START;
- }
-}
-
-void
-ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant
-{
- ao_beep(beep);
- ao_delay(ticks);
- ao_beep(0);
-}
-
-void
-ao_beep_init(void)
-{
- /* Our beeper is on P2_0, which is hooked to timer 4 using
- * configuration alternative 2
- */
- P2_0 = 0;
- P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_GPIO;
- PERCFG = (PERCFG & ~PERCFG_T4CFG_ALT_MASK) | PERCFG_T4CFG_ALT_2;
- T4CCTL0 = TxCCTLy_CMP_TOGGLE|TxCCTLy_CMP_MODE_ENABLE;
-}
+++ /dev/null
-/*
- * 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"
-
-int8_t ao_btm_stdio;
-__xdata uint8_t ao_btm_connected;
-
-#define AO_BTM_MAX_REPLY 16
-__xdata char ao_btm_reply[AO_BTM_MAX_REPLY];
-
-extern volatile __xdata struct ao_fifo ao_usart1_rx_fifo;
-
-/*
- * Read a line of data from the serial port, truncating
- * it after a few characters.
- */
-
-uint8_t
-ao_btm_get_line(void)
-{
- uint8_t ao_btm_reply_len = 0;
- char c;
-
- for (;;) {
-
- while ((c = ao_serial_pollchar()) != AO_READ_AGAIN) {
- if (ao_btm_reply_len < sizeof (ao_btm_reply))
- ao_btm_reply[ao_btm_reply_len++] = c;
- if (c == '\r' || c == '\n')
- goto done;
- }
- for (c = 0; c < 10; c++) {
- ao_delay(AO_MS_TO_TICKS(10));
- if (!ao_fifo_empty(ao_usart1_rx_fifo))
- break;
- }
- if (c == 10)
- goto done;
- }
-done:
- for (c = ao_btm_reply_len; c < sizeof (ao_btm_reply);)
- ao_btm_reply[c++] = '\0';
- return ao_btm_reply_len;
-}
-
-/*
- * Drain the serial port completely
- */
-void
-ao_btm_drain()
-{
- while (ao_btm_get_line())
- ;
-}
-
-/*
- * Set the stdio echo for the bluetooth link
- */
-void
-ao_btm_echo(uint8_t echo)
-{
- ao_stdios[ao_btm_stdio].echo = echo;
-}
-
-/*
- * Delay between command charaters; the BT module
- * can't keep up with 57600 baud
- */
-
-void
-ao_btm_putchar(char c)
-{
- ao_serial_putchar(c);
- ao_delay(1);
-}
-
-/*
- * Wait for the bluetooth device to return
- * status from the previously executed command
- */
-uint8_t
-ao_btm_wait_reply(void)
-{
- for (;;) {
- ao_btm_get_line();
- if (!strncmp(ao_btm_reply, "OK", 2))
- return 1;
- if (!strncmp(ao_btm_reply, "ERROR", 5))
- return -1;
- if (ao_btm_reply[0] == '\0')
- return 0;
- }
-}
-
-void
-ao_btm_string(__code char *cmd)
-{
- char c;
-
- while (c = *cmd++)
- ao_btm_putchar(c);
-}
-
-uint8_t
-ao_btm_cmd(__code char *cmd)
-{
- ao_btm_drain();
- ao_btm_string(cmd);
- return ao_btm_wait_reply();
-}
-
-uint8_t
-ao_btm_set_name(void)
-{
- char sn[8];
- char *s = sn + 8;
- char c;
- int n;
- ao_btm_string("ATN=TeleBT-");
- *--s = '\0';
- *--s = '\r';
- n = ao_serial_number;
- do {
- *--s = '0' + n % 10;
- } while (n /= 10);
- while ((c = *s++))
- ao_btm_putchar(c);
- return ao_btm_wait_reply();
-}
-
-uint8_t
-ao_btm_try_speed(uint8_t speed)
-{
- ao_serial_set_speed(speed);
- ao_btm_drain();
- (void) ao_btm_cmd("\rATE0\rATQ0\r");
- if (ao_btm_cmd("AT\r") == 1)
- return 1;
- return 0;
-}
-
-/*
- * A thread to initialize the bluetooth device and
- * hang around to blink the LED when connected
- */
-void
-ao_btm(void)
-{
- /*
- * Wait for the bluetooth device to boot
- */
- 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
- * if it is already running at 57600 baud, and if that doesn't work
- * then tell it to switch to 57600 from 19200 baud.
- */
- while (!ao_btm_try_speed(AO_SERIAL_SPEED_57600)) {
- ao_delay(AO_SEC_TO_TICKS(1));
- if (ao_btm_try_speed(AO_SERIAL_SPEED_19200))
- ao_btm_cmd("ATL4\r");
- ao_delay(AO_SEC_TO_TICKS(1));
- }
-
- /* Disable echo */
- ao_btm_cmd("ATE0\r");
-
- /* Enable flow control */
- ao_btm_cmd("ATC1\r");
-
- /* Set the reported name to something we can find on the host */
- ao_btm_set_name();
-
- /* Turn off status reporting */
- ao_btm_cmd("ATQ1\r");
-
- ao_btm_stdio = ao_add_stdio(ao_serial_pollchar,
- ao_serial_putchar,
- NULL);
- ao_btm_echo(0);
-
- for (;;) {
- while (!ao_btm_connected)
- ao_sleep(&ao_btm_connected);
- while (ao_btm_connected) {
- ao_led_for(AO_LED_GREEN, AO_MS_TO_TICKS(20));
- ao_delay(AO_SEC_TO_TICKS(3));
- }
- }
-}
-
-__xdata struct ao_task ao_btm_task;
-
-#if BT_LINK_ON_P2
-#define BT_PICTL_ICON PICTL_P2ICON
-#define BT_PIFG P2IFG
-#define BT_PDIR P2DIR
-#define BT_PINP P2INP
-#define BT_IEN2_PIE IEN2_P2IE
-#endif
-#if BT_LINK_ON_P1
-#define BT_PICTL_ICON PICTL_P1ICON
-#define BT_PIFG P1IFG
-#define BT_PDIR P1DIR
-#define BT_PINP P1INP
-#define BT_IEN2_PIE IEN2_P1IE
-#endif
-
-void
-ao_btm_check_link() __critical
-{
- /* Check the pin and configure the interrupt detector to wait for the
- * pin to flip the other way
- */
- if (BT_LINK_PIN) {
- ao_btm_connected = 0;
- PICTL |= BT_PICTL_ICON;
- } else {
- ao_btm_connected = 1;
- PICTL &= ~BT_PICTL_ICON;
- }
-}
-
-void
-ao_btm_isr(void)
-#if BT_LINK_ON_P1
- __interrupt 15
-#endif
-{
-#if BT_LINK_ON_P1
- P1IF = 0;
-#endif
- if (BT_PIFG & (1 << BT_LINK_PIN_INDEX)) {
- ao_btm_check_link();
- ao_wakeup(&ao_btm_connected);
- }
- BT_PIFG = 0;
-}
-
-void
-ao_btm_init (void)
-{
- ao_serial_init();
- ao_serial_set_speed(AO_SERIAL_SPEED_19200);
-
-#if BT_LINK_ON_P1
- /*
- * Configure ser reset line
- */
-
- P1_6 = 0;
- P1DIR |= (1 << 6);
-#endif
-
- /*
- * Configure link status line
- */
-
- /* Set pin to input */
- BT_PDIR &= ~(1 << BT_LINK_PIN_INDEX);
-
- /* Set pin to tri-state */
- BT_PINP |= (1 << BT_LINK_PIN_INDEX);
-
- /* Enable interrupts */
- IEN2 |= BT_IEN2_PIE;
-
- /* Check current pin state */
- ao_btm_check_link();
-
-#if BT_LINK_ON_P2
- /* Eable the pin interrupt */
- PICTL |= PICTL_P2IEN;
-#endif
-#if BT_LINK_ON_P1
- /* Enable pin interrupt */
- P1IEN |= (1 << BT_LINK_PIN_INDEX);
-#endif
-
- ao_add_task(&ao_btm_task, ao_btm, "bt");
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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 uint16_t ao_cmd_lex_i;
-__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
-
-static __xdata char cmd_line[CMD_LEN];
-static __pdata uint8_t cmd_len;
-static __pdata uint8_t cmd_i;
-
-static void
-put_string(__code char *s)
-{
- char c;
- while (c = *s++)
- putchar(c);
-}
-
-static void
-readline(void)
-{
- __pdata char c;
- if (ao_echo())
- put_string("> ");
- cmd_len = 0;
- for (;;) {
- flush();
- c = getchar();
- /* backspace/delete */
- if (c == '\010' || c == '\177') {
- if (cmd_len != 0) {
- if (ao_echo())
- put_string("\010 \010");
- --cmd_len;
- }
- continue;
- }
-
- /* ^U */
- if (c == '\025') {
- while (cmd_len != 0) {
- if (ao_echo())
- put_string("\010 \010");
- --cmd_len;
- }
- continue;
- }
-
- /* map CR to NL */
- if (c == '\r')
- c = '\n';
-
- if (c == '\n') {
- if (ao_echo())
- putchar('\n');
- break;
- }
-
- if (cmd_len >= CMD_LEN - 2) {
- if (ao_echo())
- putchar('\007');
- continue;
- }
- cmd_line[cmd_len++] = c;
- if (ao_echo())
- putchar(c);
- }
- cmd_line[cmd_len++] = '\n';
- cmd_line[cmd_len++] = '\0';
- cmd_i = 0;
-}
-
-void
-ao_cmd_lex(void)
-{
- ao_cmd_lex_c = '\n';
- if (cmd_i < cmd_len)
- ao_cmd_lex_c = cmd_line[cmd_i++];
-}
-
-static void
-putnibble(uint8_t v)
-{
- if (v < 10)
- putchar(v + '0');
- else
- putchar(v + ('a' - 10));
-}
-
-void
-ao_cmd_put16(uint16_t v)
-{
- ao_cmd_put8(v >> 8);
- ao_cmd_put8(v);
-}
-
-void
-ao_cmd_put8(uint8_t v)
-{
- putnibble((v >> 4) & 0xf);
- putnibble(v & 0xf);
-}
-
-void
-ao_cmd_white(void)
-{
- while (ao_cmd_lex_c == ' ' || ao_cmd_lex_c == '\t')
- ao_cmd_lex();
-}
-
-void
-ao_cmd_hex(void)
-{
- __pdata uint8_t r = ao_cmd_lex_error;
- uint8_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
- break;
- ao_cmd_lex_i = (ao_cmd_lex_i << 4) | n;
- r = ao_cmd_success;
- ao_cmd_lex();
- }
- if (r != ao_cmd_success)
- ao_cmd_status = r;
-}
-
-void
-ao_cmd_decimal(void)
-{
- __pdata uint8_t r = ao_cmd_lex_error;
-
- ao_cmd_lex_u32 = 0;
- ao_cmd_white();
- for(;;) {
- if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9')
- ao_cmd_lex_u32 = (ao_cmd_lex_u32 * 10) + (ao_cmd_lex_c - '0');
- else
- break;
- r = ao_cmd_success;
- ao_cmd_lex();
- }
- if (r != ao_cmd_success)
- ao_cmd_status = r;
- ao_cmd_lex_i = (uint16_t) ao_cmd_lex_u32;
-}
-
-uint8_t
-ao_match_word(__code char *word)
-{
- while (*word) {
- if (ao_cmd_lex_c != *word) {
- ao_cmd_status = ao_cmd_syntax_error;
- return 0;
- }
- word++;
- ao_cmd_lex();
- }
- return 1;
-}
-
-static void
-eol(void)
-{
- while (ao_cmd_lex_c != '\n')
- ao_cmd_lex();
-}
-
-static void
-echo(void)
-{
- ao_cmd_hex();
- if (ao_cmd_status == ao_cmd_success)
- ao_stdios[ao_cur_stdio].echo = ao_cmd_lex_i != 0;
-}
-
-static void
-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_panic(AO_PANIC_REBOOT);
-}
-
-static void
-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
- printf("log-format %u\n", ao_log_format);
-#endif
- printf("software-version %s\n", ao_version);
-}
-
-#define NUM_CMDS 11
-
-static __code struct ao_cmds *__xdata (ao_cmds[NUM_CMDS]);
-static __pdata uint8_t ao_ncmds;
-
-static void
-help(void)
-{
- register uint8_t cmds;
- register uint8_t cmd;
- register __code struct ao_cmds * cs;
-
- for (cmds = 0; cmds < ao_ncmds; cmds++) {
- cs = ao_cmds[cmds];
- for (cmd = 0; cs[cmd].func; cmd++)
- printf("%-45s %s\n",
- cs[cmd].help,
- cs[cmd].help+1+strlen(cs[cmd].help));
- }
-}
-
-static void
-report(void)
-{
- switch(ao_cmd_status) {
- case ao_cmd_lex_error:
- case ao_cmd_syntax_error:
- puts("Syntax error");
- ao_cmd_status = 0;
- break;
- }
-}
-
-void
-ao_cmd_register(__code struct ao_cmds *cmds)
-{
- if (ao_ncmds >= NUM_CMDS)
- ao_panic(AO_PANIC_CMD);
- ao_cmds[ao_ncmds++] = cmds;
-}
-
-void
-ao_cmd(void)
-{
- char c;
- uint8_t cmd, cmds;
- __code struct ao_cmds * __xdata cs;
- void (*__xdata func)(void);
-
- for (;;) {
- readline();
- ao_cmd_lex();
- ao_cmd_white();
- c = ao_cmd_lex_c;
- ao_cmd_lex();
- if (c == '\r' || c == '\n')
- continue;
- func = (void (*)(void)) NULL;
- for (cmds = 0; cmds < ao_ncmds; cmds++) {
- cs = ao_cmds[cmds];
- for (cmd = 0; cs[cmd].func; cmd++)
- if (cs[cmd].help[0] == c) {
- func = cs[cmd].func;
- break;
- }
- if (func)
- break;
- }
- if (func)
- (*func)();
- else
- ao_cmd_status = ao_cmd_syntax_error;
- report();
- }
-}
-
-__xdata struct ao_task ao_cmd_task;
-
-__code struct ao_cmds ao_base_cmds[] = {
- { help, "?\0Help" },
- { ao_task_info, "T\0Show tasks" },
- { echo, "E <0 off, 1 on>\0Set echo mode" },
- { ao_reboot, "r eboot\0Reboot" },
- { version, "v\0Version" },
- { 0, NULL },
-};
-
-void
-ao_cmd_init(void)
-{
- ao_cmd_register(&ao_base_cmds[0]);
- ao_add_task(&ao_cmd_task, ao_cmd, "cmd");
-}
+++ /dev/null
-/*
- * 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_spi_slow() (U0GCR = (UxGCR_CPOL_NEGATIVE | \
- UxGCR_CPHA_FIRST_EDGE | \
- UxGCR_ORDER_MSB | \
- (13 << UxGCR_BAUD_E_SHIFT)))
-
-#define ao_spi_fast() (U0GCR = (UxGCR_CPOL_NEGATIVE | \
- UxGCR_CPHA_FIRST_EDGE | \
- UxGCR_ORDER_MSB | \
- (17 << UxGCR_BAUD_E_SHIFT)))
-
-#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_setup ao_companion_setup;
-
-__xdata uint16_t ao_companion_data[AO_COMPANION_MAX_CHANNELS];
-__pdata uint8_t ao_companion_running;
-__xdata uint8_t ao_companion_mutex;
-
-static void
-ao_companion_send_command(uint8_t command)
-{
- ao_companion_command.command = command;
- ao_companion_command.flight_state = ao_flight_state;
- ao_companion_command.tick = ao_time();
- ao_companion_command.serial = ao_serial_number;
- ao_companion_command.flight = ao_flight_number;
- ao_spi_send(&ao_companion_command, sizeof (ao_companion_command));
-}
-
-static uint8_t
-ao_companion_get_setup(void)
-{
- COMPANION_SELECT();
- ao_companion_send_command(AO_COMPANION_SETUP);
- ao_spi_recv(&ao_companion_setup, sizeof (ao_companion_setup));
- COMPANION_DESELECT();
- return (ao_companion_setup.board_id ==
- ~ao_companion_setup.board_id_inverse);
-}
-
-static void
-ao_companion_get_data(void)
-{
- COMPANION_SELECT();
- ao_companion_send_command(AO_COMPANION_FETCH);
- ao_mutex_get(&ao_companion_mutex);
- ao_spi_recv(&ao_companion_data, ao_companion_setup.channels * 2);
- ao_mutex_put(&ao_companion_mutex);
- COMPANION_DESELECT();
-}
-
-static void
-ao_companion_notify(void)
-{
- COMPANION_SELECT();
- ao_companion_send_command(AO_COMPANION_NOTIFY);
- COMPANION_DESELECT();
-}
-
-void
-ao_companion(void)
-{
- uint8_t i;
- while (!ao_flight_number)
- ao_sleep(&ao_flight_number);
- for (i = 0; i < 10; i++) {
- ao_delay(AO_SEC_TO_TICKS(1));
- if ((ao_companion_running = ao_companion_get_setup()))
- break;
- }
- while (ao_companion_running) {
- ao_alarm(ao_companion_setup.update_period);
- if (ao_sleep(DATA_TO_XDATA(&ao_flight_state)))
- ao_companion_get_data();
- else
- ao_companion_notify();
- }
- ao_exit();
-}
-
-void
-ao_companion_status(void) __reentrant
-{
- uint8_t i;
- printf("Companion running: %d\n", ao_companion_running);
- printf("device: %d\n", ao_companion_setup.board_id);
- printf("update period: %d\n", ao_companion_setup.update_period);
- printf("channels: %d\n", ao_companion_setup.channels);
- printf("data:");
- for(i = 0; i < ao_companion_setup.channels; i++)
- printf(" %5u", ao_companion_data[i]);
- printf("\n");
-}
-
-__code struct ao_cmds ao_companion_cmds[] = {
- { ao_companion_status, "L\0Companion link status" },
- { 0, NULL },
-};
-
-static __xdata struct ao_task ao_companion_task;
-
-void
-ao_companion_init(void)
-{
- COMPANION_CS_PORT |= COMPANION_CS_MASK; /* raise all CS pins */
- COMPANION_CS_DIR |= COMPANION_CS_MASK; /* set CS pins as outputs */
- COMPANION_CS_SEL &= ~COMPANION_CS_MASK; /* set CS pins as GPIO */
-
- ao_cmd_register(&ao_companion_cmds[0]);
- ao_add_task(&ao_companion_task, ao_companion, "companion");
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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_config ao_config;
-__pdata uint8_t ao_config_loaded;
-__pdata uint8_t ao_config_dirty;
-__xdata uint8_t ao_config_mutex;
-
-#define AO_CONFIG_DEFAULT_MAIN_DEPLOY 250
-#define AO_CONFIG_DEFAULT_RADIO_CHANNEL 0
-#define AO_CONFIG_DEFAULT_CALLSIGN "N0CALL"
-#define AO_CONFIG_DEFAULT_ACCEL_ZERO_G 16000
-#define AO_CONFIG_DEFAULT_APOGEE_DELAY 0
-#define AO_CONFIG_DEFAULT_IGNITE_MODE AO_IGNITE_MODE_DUAL
-#define AO_CONFIG_DEFAULT_PAD_ORIENTATION AO_PAD_ORIENTATION_ANTENNA_UP
-#if HAS_EEPROM
-#ifndef USE_INTERNAL_FLASH
-#error Please define USE_INTERNAL_FLASH
-#endif
-#endif
-#if USE_INTERNAL_FLASH
-#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX ao_storage_config
-#else
-#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX ((uint32_t) 192 * (uint32_t) 1024)
-#endif
-
-#if HAS_EEPROM
-static void
-_ao_config_put(void)
-{
- ao_storage_setup();
- ao_storage_erase(ao_storage_config);
- ao_storage_write(ao_storage_config, &ao_config, sizeof (ao_config));
- ao_log_write_erase(0);
- ao_storage_flush();
-}
-
-void
-ao_config_put(void)
-{
- ao_mutex_get(&ao_config_mutex);
- _ao_config_put();
- ao_mutex_put(&ao_config_mutex);
-}
-#endif
-
-static void
-_ao_config_get(void)
-{
- if (ao_config_loaded)
- return;
-#if HAS_EEPROM
- ao_storage_setup();
- ao_storage_read(ao_storage_config, &ao_config, sizeof (ao_config));
-#endif
- if (ao_config.major != AO_CONFIG_MAJOR) {
- ao_config.major = AO_CONFIG_MAJOR;
- ao_config.minor = 0;
- 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);
- }
- if (ao_config.minor < AO_CONFIG_MINOR) {
- /* Fixups for minor version 1 */
- if (ao_config.minor < 1)
- ao_config.apogee_delay = AO_CONFIG_DEFAULT_APOGEE_DELAY;
- /* Fixups for minor version 2 */
- if (ao_config.minor < 2) {
- ao_config.accel_plus_g = 0;
- ao_config.accel_minus_g = 0;
- }
- /* Fixups for minor version 3 */
- if (ao_config.minor < 3)
- ao_config.radio_cal = ao_radio_cal;
- /* Fixups for minor version 4 */
- if (ao_config.minor < 4)
- ao_config.flight_log_max = AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX;
- /* Fixupes for minor version 5 */
- if (ao_config.minor < 5)
- ao_config.ignite_mode = AO_CONFIG_DEFAULT_IGNITE_MODE;
- if (ao_config.minor < 6)
- ao_config.pad_orientation = AO_CONFIG_DEFAULT_PAD_ORIENTATION;
- if (ao_config.minor < 7)
- ao_config.radio_setting = ao_config.radio_cal;
- if (ao_config.minor < 8)
- ao_config.radio_enable = TRUE;
- ao_config.minor = AO_CONFIG_MINOR;
- ao_config_dirty = 1;
- }
- ao_config_loaded = 1;
-}
-
-static void
-_ao_config_edit_start(void)
-{
- ao_mutex_get(&ao_config_mutex);
- _ao_config_get();
-}
-
-static void
-_ao_config_edit_finish(void)
-{
- ao_config_dirty = 1;
- ao_mutex_put(&ao_config_mutex);
-}
-
-void
-ao_config_get(void)
-{
- _ao_config_edit_start();
- ao_mutex_put(&ao_config_mutex);
-}
-
-void
-ao_config_callsign_show(void)
-{
- printf ("Callsign: \"%s\"\n", ao_config.callsign);
-}
-
-void
-ao_config_callsign_set(void) __reentrant
-{
- uint8_t c;
- static __xdata char callsign[AO_MAX_CALLSIGN + 1];
-
- memset(callsign, '\0', sizeof callsign);
- ao_cmd_white();
- c = 0;
- while (ao_cmd_lex_c != '\n') {
- if (c < AO_MAX_CALLSIGN)
- callsign[c++] = ao_cmd_lex_c;
- else
- ao_cmd_status = ao_cmd_lex_error;
- ao_cmd_lex();
- }
- if (ao_cmd_status != ao_cmd_success)
- return;
- _ao_config_edit_start();
- memcpy(&ao_config.callsign, &callsign,
- AO_MAX_CALLSIGN + 1);
- _ao_config_edit_finish();
-}
-
-void
-ao_config_radio_channel_show(void) __reentrant
-{
- printf("Radio channel: %d\n",
- ao_config.radio_channel);
-}
-
-void
-ao_config_radio_channel_set(void) __reentrant
-{
- ao_cmd_decimal();
- if (ao_cmd_status != ao_cmd_success)
- return;
- _ao_config_edit_start();
- ao_config.radio_channel = ao_cmd_lex_i;
- _ao_config_edit_finish();
- ao_radio_recv_abort();
-}
-
-#if HAS_ADC
-
-void
-ao_config_main_deploy_show(void) __reentrant
-{
- printf("Main deploy: %d meters\n",
- ao_config.main_deploy);
-}
-
-void
-ao_config_main_deploy_set(void) __reentrant
-{
- ao_cmd_decimal();
- if (ao_cmd_status != ao_cmd_success)
- return;
- _ao_config_edit_start();
- ao_config.main_deploy = ao_cmd_lex_i;
- _ao_config_edit_finish();
-}
-
-#if HAS_ACCEL
-void
-ao_config_accel_calibrate_show(void) __reentrant
-{
- printf("Accel cal +1g: %d -1g: %d\n",
- ao_config.accel_plus_g, ao_config.accel_minus_g);
-}
-
-#define ACCEL_CALIBRATE_SAMPLES 1024
-#define ACCEL_CALIBRATE_SHIFT 10
-
-static int16_t
-ao_config_accel_calibrate_auto(char *orientation) __reentrant
-{
- uint16_t i;
- int32_t accel_total;
- uint8_t cal_adc_ring;
-
- printf("Orient antenna %s and press a key...", orientation);
- flush();
- (void) getchar();
- puts("\r\n"); flush();
- puts("Calibrating..."); flush();
- i = ACCEL_CALIBRATE_SAMPLES;
- accel_total = 0;
- cal_adc_ring = ao_sample_adc;
- while (i) {
- ao_sleep(DATA_TO_XDATA(&ao_sample_adc));
- while (i && cal_adc_ring != ao_sample_adc) {
- accel_total += (int32_t) ao_adc_ring[cal_adc_ring].accel;
- cal_adc_ring = ao_adc_ring_next(cal_adc_ring);
- i--;
- }
- }
- return accel_total >> ACCEL_CALIBRATE_SHIFT;
-}
-
-void
-ao_config_accel_calibrate_set(void) __reentrant
-{
- int16_t up, down;
- ao_cmd_decimal();
- if (ao_cmd_status != ao_cmd_success)
- return;
- if (ao_cmd_lex_i == 0) {
- up = ao_config_accel_calibrate_auto("up");
- down = ao_config_accel_calibrate_auto("down");
- } else {
- up = ao_cmd_lex_i;
- ao_cmd_decimal();
- if (ao_cmd_status != ao_cmd_success)
- return;
- down = ao_cmd_lex_i;
- }
- if (up >= down) {
- printf("Invalid accel: up (%d) down (%d)\n",
- up, down);
- return;
- }
- _ao_config_edit_start();
- ao_config.accel_plus_g = up;
- ao_config.accel_minus_g = down;
- _ao_config_edit_finish();
-}
-#endif /* HAS_ACCEL */
-
-void
-ao_config_apogee_delay_show(void) __reentrant
-{
- printf("Apogee delay: %d seconds\n",
- ao_config.apogee_delay);
-}
-
-void
-ao_config_apogee_delay_set(void) __reentrant
-{
- ao_cmd_decimal();
- if (ao_cmd_status != ao_cmd_success)
- return;
- _ao_config_edit_start();
- ao_config.apogee_delay = ao_cmd_lex_i;
- _ao_config_edit_finish();
-}
-
-#endif /* HAS_ADC */
-
-void
-ao_config_radio_cal_show(void) __reentrant
-{
- printf("Radio cal: %ld\n", ao_config.radio_cal);
-}
-
-void
-ao_config_radio_cal_set(void) __reentrant
-{
- ao_cmd_decimal();
- if (ao_cmd_status != ao_cmd_success)
- return;
- _ao_config_edit_start();
- ao_config.radio_setting = ao_config.radio_cal = ao_cmd_lex_u32;
- _ao_config_edit_finish();
-}
-
-#if HAS_EEPROM
-void
-ao_config_log_show(void) __reentrant
-{
- printf("Max flight log: %d kB\n", (int16_t) (ao_config.flight_log_max >> 10));
-}
-
-void
-ao_config_log_set(void) __reentrant
-{
- uint16_t block = (uint16_t) (ao_storage_block >> 10);
- uint16_t config = (uint16_t) (ao_storage_config >> 10);
-
- ao_cmd_decimal();
- if (ao_cmd_status != ao_cmd_success)
- return;
- if (ao_log_present())
- printf("Storage must be empty before changing log size\n");
- else if (block > 1024 && (ao_cmd_lex_i & (block - 1)))
- printf("Flight log size must be multiple of %d kB\n", block);
- else if (ao_cmd_lex_i > config)
- printf("Flight log max %d kB\n", config);
- else {
- _ao_config_edit_start();
- ao_config.flight_log_max = (uint32_t) ao_cmd_lex_i << 10;
- _ao_config_edit_finish();
- }
-}
-#endif /* HAS_EEPROM */
-
-#if HAS_IGNITE
-void
-ao_config_ignite_mode_show(void) __reentrant
-{
- printf("Ignite mode: %d\n", ao_config.ignite_mode);
-}
-
-void
-ao_config_ignite_mode_set(void) __reentrant
-{
- ao_cmd_decimal();
- if (ao_cmd_status != ao_cmd_success)
- return;
- _ao_config_edit_start();
- ao_config.ignite_mode = ao_cmd_lex_i;
- _ao_config_edit_finish();
-}
-#endif
-
-#if HAS_ACCEL
-void
-ao_config_pad_orientation_show(void) __reentrant
-{
- printf("Pad orientation: %d\n", ao_config.pad_orientation);
-}
-
-void
-ao_config_pad_orientation_set(void) __reentrant
-{
- ao_cmd_decimal();
- if (ao_cmd_status != ao_cmd_success)
- return;
- _ao_config_edit_start();
- ao_cmd_lex_i &= 1;
- if (ao_config.pad_orientation != ao_cmd_lex_i) {
- uint16_t t;
- t = ao_config.accel_plus_g;
- ao_config.accel_plus_g = 0x7fff - ao_config.accel_minus_g;
- ao_config.accel_minus_g = 0x7fff - t;
- }
- ao_config.pad_orientation = ao_cmd_lex_i;
- _ao_config_edit_finish();
-}
-#endif
-
-void
-ao_config_radio_setting_show(void) __reentrant
-{
- printf("Radio setting: %ld\n", ao_config.radio_setting);
-}
-
-void
-ao_config_radio_setting_set(void) __reentrant
-{
- ao_cmd_decimal();
- if (ao_cmd_status != ao_cmd_success)
- return;
- _ao_config_edit_start();
- ao_config.radio_setting = ao_cmd_lex_u32;
- ao_config.radio_channel = 0;
- _ao_config_edit_finish();
- ao_radio_recv_abort();
-}
-
-void
-ao_config_radio_enable_show(void) __reentrant
-{
- printf("Radio enable: %d\n", ao_config.radio_enable);
-}
-
-void
-ao_config_radio_enable_set(void) __reentrant
-{
- ao_cmd_decimal();
- if (ao_cmd_status != ao_cmd_success)
- return;
- _ao_config_edit_start();
- ao_config.radio_enable = ao_cmd_lex_i;
- _ao_config_edit_finish();
-}
-
-struct ao_config_var {
- __code char *str;
- void (*set)(void) __reentrant;
- void (*show)(void) __reentrant;
-};
-
-static void
-ao_config_help(void) __reentrant;
-
-static void
-ao_config_show(void) __reentrant;
-
-static void
-ao_config_write(void) __reentrant;
-
-__code struct ao_config_var ao_config_vars[] = {
-#if HAS_ADC
- { "m <meters>\0Main deploy (in meters)",
- ao_config_main_deploy_set, ao_config_main_deploy_show, },
- { "d <delay>\0Apogee delay (in seconds)",
- ao_config_apogee_delay_set, ao_config_apogee_delay_show },
-#endif /* HAS_ADC */
- { "r <channel>\0Radio channel (freq = 434.550 + chan * .1)",
- ao_config_radio_channel_set, ao_config_radio_channel_show },
- { "c <call>\0Callsign (8 char max)",
- ao_config_callsign_set, ao_config_callsign_show },
- { "R <setting>\0Radio freq control (freq = 434.550 * setting/cal)",
- ao_config_radio_setting_set, ao_config_radio_setting_show },
- { "e <0 disable, 1 enable>\0Enable telemetry and RDF",
- ao_config_radio_enable_set, ao_config_radio_enable_show },
-#if HAS_ACCEL
- { "a <+g> <-g>\0Accel calib (0 for auto)",
- ao_config_accel_calibrate_set,ao_config_accel_calibrate_show },
-#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
- { "l <size>\0Flight log size in kB",
- ao_config_log_set, ao_config_log_show },
-#endif
-#if HAS_IGNITE
- { "i <0 dual, 1 apogee, 2 main>\0Set igniter mode",
- ao_config_ignite_mode_set, ao_config_ignite_mode_show },
-#endif
-#if HAS_ACCEL
- { "o <0 antenna up, 1 antenna down>\0Set pad orientation",
- ao_config_pad_orientation_set,ao_config_pad_orientation_show },
-#endif
- { "s\0Show",
- ao_config_show, 0 },
-#if HAS_EEPROM
- { "w\0Write to eeprom",
- ao_config_write, 0 },
-#endif
- { "?\0Help",
- ao_config_help, 0 },
- { 0, 0, 0 }
-};
-
-void
-ao_config_set(void)
-{
- char c;
- uint8_t cmd;
- void (*__xdata func)(void) __reentrant;
-
- ao_cmd_white();
- c = ao_cmd_lex_c;
- ao_cmd_lex();
- func = 0;
- for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
- if (ao_config_vars[cmd].str[0] == c) {
- (*ao_config_vars[cmd].set)();
- return;
- }
- ao_cmd_status = ao_cmd_syntax_error;
-}
-
-static void
-ao_config_help(void) __reentrant
-{
- uint8_t cmd;
- for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
- printf("%-20s %s\n",
- ao_config_vars[cmd].str,
- ao_config_vars[cmd].str+1+strlen(ao_config_vars[cmd].str));
-}
-
-static void
-ao_config_show(void) __reentrant
-{
- uint8_t cmd;
- printf("Config version: %d.%d\n",
- ao_config.major, ao_config.minor);
- for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
- if (ao_config_vars[cmd].show)
- (*ao_config_vars[cmd].show)();
-}
-
-#if HAS_EEPROM
-static void
-ao_config_write(void) __reentrant
-{
- uint8_t saved = 0;
- ao_mutex_get(&ao_config_mutex);
- if (ao_config_dirty) {
- _ao_config_put();
- ao_config_dirty = 0;
- saved = 1;
- }
- ao_mutex_put(&ao_config_mutex);
- if (saved)
- puts("Saved");
- else
- puts("Nothing to save");
-}
-#endif
-
-__code struct ao_cmds ao_config_cmds[] = {
- { ao_config_set, "c <var> <value>\0Set config variable (? for help, s to show)" },
- { 0, NULL },
-};
-
-void
-ao_config_init(void)
-{
- ao_cmd_register(&ao_config_cmds[0]);
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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.
- */
-
-#if !defined(AO_CONVERT_TEST) && !defined(AO_FLIGHT_TEST)
-#include "ao.h"
-#endif
-
-static const int16_t altitude_table[] = {
-#include "altitude.h"
-};
-
-#define ALT_FRAC_SCALE (1 << ALT_FRAC_BITS)
-#define ALT_FRAC_MASK (ALT_FRAC_SCALE - 1)
-
-int16_t
-ao_pres_to_altitude(int16_t pres) __reentrant
-{
- uint8_t o;
- int16_t part;
-
- if (pres < 0)
- pres = 0;
- o = pres >> ALT_FRAC_BITS;
- part = pres & ALT_FRAC_MASK;
-
- return ((int32_t) altitude_table[o] * (ALT_FRAC_SCALE - part) +
- (int32_t) altitude_table[o+1] * part + (ALT_FRAC_SCALE >> 1)) >> ALT_FRAC_BITS;
-}
-
-int16_t
-ao_altitude_to_pres(int16_t alt) __reentrant
-{
- int16_t span, sub_span;
- uint8_t l, h, m;
- int32_t pres;
-
- l = 0;
- h = NALT - 1;
- while ((h - l) != 1) {
- m = (l + h) >> 1;
- if (altitude_table[m] < alt)
- h = m;
- else
- l = m;
- }
- span = altitude_table[l] - altitude_table[h];
- sub_span = altitude_table[l] - alt;
- pres = ((((int32_t) l * (span - sub_span) + (int32_t) h * sub_span) << ALT_FRAC_BITS) + (span >> 1)) / span;
- if (pres > 32767)
- pres = 32767;
- if (pres < 0)
- pres = 0;
- return (int16_t) pres;
-}
-
-int16_t
-ao_temp_to_dC(int16_t temp) __reentrant
-{
- int16_t ret;
-
- /* Output voltage at 0°C = 0.755V
- * Coefficient = 0.00247V/°C
- * Reference voltage = 1.25V
- *
- * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247
- * = (value - 19791.268) / 32768 * 1.25 / 0.00247
- * ≃ (value - 19791) * 1012 / 65536
- */
- ret = ((temp - 19791) * 1012L) >> 16;
- return ret;
-}
+++ /dev/null
-/*
- * 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.
- */
-
-#include <stdint.h>
-#define AO_CONVERT_TEST
-#include "ao_host.h"
-#include "ao_convert.c"
-
-#define STEP 1
-
-static inline i_abs(int i) { return i < 0 ? -i : i; }
-
-main ()
-{
- int i;
- int16_t p_to_a, p_to_a_to_p;
- int16_t a_to_p, a_to_p_to_a;
- int max_p_error = 0, max_p_error_p = -1;
- int max_a_error = 0, max_a_error_a = -1;
- int p_error;
- int a_error;
- int ret = 0;
-
- for (i = 0; i < 32767 + STEP; i += STEP) {
- if (i > 32767)
- i = 32767;
- p_to_a = ao_pres_to_altitude(i);
- p_to_a_to_p = ao_altitude_to_pres(p_to_a);
- p_error = i_abs(p_to_a_to_p - i);
- if (p_error > max_p_error) {
- max_p_error = p_error;
- max_p_error_p = i;
- }
-// printf ("pres %d alt %d pres %d\n",
-// i, p_to_a, p_to_a_to_p);
- }
- for (i = -1578; i < 15835 + STEP; i += STEP) {
- if (i > 15835)
- i = 15835;
- a_to_p = ao_altitude_to_pres(i);
- a_to_p_to_a = ao_pres_to_altitude(a_to_p);
- a_error = i_abs(a_to_p_to_a - i);
- if (a_error > max_a_error) {
- max_a_error = a_error;
- max_a_error_a = i;
- }
-// printf ("alt %d pres %d alt %d\n",
-// i, a_to_p, a_to_p_to_a);
- }
- if (max_p_error > 2) {
- printf ("max p error %d at %d\n", max_p_error,
- max_p_error_p);
- ret++;
- }
- if (max_a_error > 1) {
- printf ("max a error %d at %d\n", max_a_error,
- max_a_error_a);
- ret++;
- }
- return ret;
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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_pins.h"
-
-static void
-ao_dbg_send_bits(uint8_t msk, uint8_t val) __reentrant
-{
- DBG_PORT = (DBG_PORT & ~msk) | (val & msk);
- _asm
- nop
- nop
- _endasm;
-}
-
-void
-ao_dbg_send_byte(uint8_t byte)
-{
- __pdata uint8_t b, d;
-
- DBG_PORT |= DBG_DATA;
- DBG_PORT_DIR |= DBG_DATA;
- for (b = 0; b < 8; b++) {
- d = 0;
- if (byte & 0x80)
- d = DBG_DATA;
- byte <<= 1;
- ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, DBG_CLOCK|d);
- ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, 0 |d);
- }
- DBG_PORT_DIR &= ~DBG_DATA;
-}
-
-uint8_t
-ao_dbg_recv_byte(void)
-{
- __pdata uint8_t byte, b;
-
- byte = 0;
- for (b = 0; b < 8; b++) {
- byte = byte << 1;
- ao_dbg_send_bits(DBG_CLOCK, DBG_CLOCK);
- if (DBG_DATA_PIN)
- byte |= 1;
- ao_dbg_send_bits(DBG_CLOCK, 0);
- }
- return byte;
-}
-
-/* 8051 instructions
- */
-#define NOP 0x00
-#define MOV_direct_data 0x75
-#define LJMP 0x02
-#define MOV_Rn_data(n) (0x78 | (n))
-#define DJNZ_Rn_rel(n) (0xd8 | (n))
-#define MOV_A_direct 0xe5
-#define MOV_direct1_direct2 0x85
-#define MOV_direct_A 0xf5
-#define MOV_DPTR_data16 0x90
-#define MOV_A_data 0x74
-#define MOVX_atDPTR_A 0xf0
-#define MOVX_A_atDPTR 0xe0
-#define INC_DPTR 0xa3
-#define TRAP 0xa5
-#define SJMP 0x80
-#define JB 0x20
-
-#define DEBUG_INSTR(l) (0x54 | (l))
-
-#define SFR_PSW 0xD0
-#define SFR_DPL0 0x82
-#define SFR_DPH0 0x83
-#define SFR_DPL1 0x84
-#define SFR_DPH1 0x85
-
-__pdata uint8_t save_acc;
-__pdata uint8_t save_psw;
-__pdata uint8_t save_dpl0;
-__pdata uint8_t save_dph0;
-__pdata uint8_t save_dpl1;
-__pdata uint8_t save_dph1;
-
-static uint8_t
-ao_dbg_inst1(uint8_t a) __reentrant
-{
- ao_dbg_send_byte(DEBUG_INSTR(1));
- ao_dbg_send_byte(a);
- return ao_dbg_recv_byte();
-}
-
-static uint8_t
-ao_dbg_inst2(uint8_t a, uint8_t b) __reentrant
-{
- ao_dbg_send_byte(DEBUG_INSTR(2));
- ao_dbg_send_byte(a);
- ao_dbg_send_byte(b);
- return ao_dbg_recv_byte();
-}
-
-static uint8_t
-ao_dbg_inst3(uint8_t a, uint8_t b, uint8_t c) __reentrant
-{
- ao_dbg_send_byte(DEBUG_INSTR(3));
- ao_dbg_send_byte(a);
- ao_dbg_send_byte(b);
- ao_dbg_send_byte(c);
- return ao_dbg_recv_byte();
-}
-
-void
-ao_dbg_start_transfer(uint16_t addr)
-{
- save_acc = ao_dbg_inst1(NOP);
- save_psw = ao_dbg_inst2(MOV_A_direct, SFR_PSW);
- save_dpl0 = ao_dbg_inst2(MOV_A_direct, SFR_DPL0);
- save_dph0 = ao_dbg_inst2(MOV_A_direct, SFR_DPH0);
- save_dpl1 = ao_dbg_inst2(MOV_A_direct, SFR_DPL1);
- save_dph1 = ao_dbg_inst2(MOV_A_direct, SFR_DPH1);
- ao_dbg_inst3(MOV_DPTR_data16, addr >> 8, addr);
-}
-
-void
-ao_dbg_end_transfer(void)
-{
- ao_dbg_inst3(MOV_direct_data, SFR_DPL0, save_dpl0);
- ao_dbg_inst3(MOV_direct_data, SFR_DPH0, save_dph0);
- ao_dbg_inst3(MOV_direct_data, SFR_DPL1, save_dpl1);
- ao_dbg_inst3(MOV_direct_data, SFR_DPH1, save_dph1);
- ao_dbg_inst3(MOV_direct_data, SFR_PSW, save_psw);
- ao_dbg_inst2(MOV_A_data, save_acc);
-}
-
-void
-ao_dbg_write_byte(uint8_t byte)
-{
- ao_dbg_inst2(MOV_A_data, byte);
- ao_dbg_inst1(MOVX_atDPTR_A);
- ao_dbg_inst1(INC_DPTR);
-}
-
-uint8_t
-ao_dbg_read_byte(void)
-{
- ao_dbg_inst1(MOVX_A_atDPTR);
- return ao_dbg_inst1(INC_DPTR);
-}
-
-static void
-ao_dbg_set_pins(void)
-{
- /* Make the DBG pins GPIOs. On TeleMetrum, this will
- * disable the SPI link, so don't expect SPI to work after
- * using the debugger.
- */
- DBG_PORT_SEL &= ~(DBG_CLOCK|DBG_DATA|DBG_RESET_N);
-
- /* make DBG_DATA tri-state */
- DBG_PORT_INP |= DBG_DATA;
-
- /* Raise RESET_N and CLOCK */
- DBG_PORT |= DBG_RESET_N | DBG_CLOCK;
-
- /* RESET_N and CLOCK are outputs now */
- DBG_PORT_DIR |= DBG_RESET_N | DBG_CLOCK;
- DBG_PORT_DIR &= ~DBG_DATA;
-}
-
-static void
-ao_dbg_long_delay(void)
-{
- uint8_t n;
-
- for (n = 0; n < 20; n++)
- _asm nop _endasm;
-}
-
-#define AO_RESET_LOW_DELAY AO_MS_TO_TICKS(100)
-#define AO_RESET_HIGH_DELAY AO_MS_TO_TICKS(100)
-
-void
-ao_dbg_debug_mode(void)
-{
- ao_dbg_set_pins();
- ao_dbg_long_delay();
- ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
- ao_dbg_long_delay();
- ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA| 0 );
- ao_delay(AO_RESET_LOW_DELAY);
- ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
- ao_dbg_long_delay();
- ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA| 0 );
- ao_dbg_long_delay();
- ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
- ao_dbg_long_delay();
- ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA|DBG_RESET_N);
- ao_delay(AO_RESET_HIGH_DELAY);
-}
-
-void
-ao_dbg_reset(void)
-{
- ao_dbg_set_pins();
- ao_dbg_long_delay();
- ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
- ao_dbg_long_delay();
- ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
- ao_delay(AO_RESET_LOW_DELAY);
- ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
- ao_dbg_long_delay();
- ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
- ao_dbg_long_delay();
- ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
- ao_dbg_long_delay();
- ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
- ao_delay(AO_RESET_HIGH_DELAY);
-}
-
-static void
-debug_enable(void)
-{
- ao_dbg_debug_mode();
-}
-
-static void
-debug_reset(void)
-{
- ao_dbg_reset();
-}
-
-static void
-debug_put(void)
-{
- for (;;) {
- ao_cmd_white ();
- if (ao_cmd_lex_c == '\n')
- break;
- ao_cmd_hex();
- if (ao_cmd_status != ao_cmd_success)
- break;
- ao_dbg_send_byte(ao_cmd_lex_i);
- }
-}
-
-static void
-debug_get(void)
-{
- __pdata uint16_t count;
- __pdata uint16_t i;
- __pdata uint8_t byte;
- ao_cmd_hex();
- if (ao_cmd_status != ao_cmd_success)
- return;
- count = ao_cmd_lex_i;
- if (count > 256) {
- ao_cmd_status = ao_cmd_syntax_error;
- return;
- }
- for (i = 0; i < count; i++) {
- if (i && (i & 7) == 0)
- putchar('\n');
- byte = ao_dbg_recv_byte();
- ao_cmd_put8(byte);
- putchar(' ');
- }
- putchar('\n');
-}
-
-static uint8_t
-getnibble(void)
-{
- __pdata char c;
-
- c = getchar();
- if ('0' <= c && c <= '9')
- return c - '0';
- if ('a' <= c && c <= 'f')
- return c - ('a' - 10);
- if ('A' <= c && c <= 'F')
- return c - ('A' - 10);
- ao_cmd_status = ao_cmd_lex_error;
- return 0;
-}
-
-static void
-debug_input(void)
-{
- __pdata uint16_t count;
- __pdata uint16_t addr;
- __pdata uint8_t b;
- __pdata uint8_t i;
-
- ao_cmd_hex();
- count = ao_cmd_lex_i;
- ao_cmd_hex();
- addr = ao_cmd_lex_i;
- if (ao_cmd_status != ao_cmd_success)
- return;
- ao_dbg_start_transfer(addr);
- i = 0;
- while (count--) {
- if (!(i++ & 7))
- putchar('\n');
- b = ao_dbg_read_byte();
- ao_cmd_put8(b);
- }
- ao_dbg_end_transfer();
- putchar('\n');
-}
-
-static void
-debug_output(void)
-{
- __pdata uint16_t count;
- __pdata uint16_t addr;
- __pdata uint8_t b;
-
- ao_cmd_hex();
- count = ao_cmd_lex_i;
- ao_cmd_hex();
- addr = ao_cmd_lex_i;
- if (ao_cmd_status != ao_cmd_success)
- return;
- ao_dbg_start_transfer(addr);
- while (count--) {
- b = getnibble() << 4;
- b |= getnibble();
- if (ao_cmd_status != ao_cmd_success)
- return;
- ao_dbg_write_byte(b);
- }
- ao_dbg_end_transfer();
-}
-
-__code struct ao_cmds ao_dbg_cmds[7] = {
- { debug_enable, "D\0Enable debug" },
- { debug_get, "G <count>\0Get data" },
- { debug_input, "I <count> <addr>\0Input <count> at <addr>" },
- { debug_output, "O <count> <addr>\0Output <count> at <addr>" },
- { debug_put, "P <byte> ...\0Put data" },
- { debug_reset, "R\0Reset" },
- { 0, NULL },
-};
-
-void
-ao_dbg_init(void)
-{
- ao_cmd_register(&ao_dbg_cmds[0]);
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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 NUM_DMA 5
-
-/*
- * The config address for DMA0 is programmed
- * separately from that of DMA1-4, but for simplicity,
- * we make them all contiguous.
- */
-
-static __xdata struct cc_dma_channel ao_dma_config[NUM_DMA];
-static __xdata uint8_t * __xdata ao_dma_done[NUM_DMA];
-static __data uint8_t ao_next_dma;
-
-uint8_t
-ao_dma_alloc(__xdata uint8_t *done)
-{
- uint8_t id;
-
- if (ao_next_dma == NUM_DMA)
- ao_panic(AO_PANIC_DMA);
- id = ao_next_dma++;
- ao_dma_done[id] = done;
-
- /* When the first dma object is allocated, set up the DMA
- * controller
- */
- if (id == 0) {
- DMAIRQ = 0;
- DMAIF = 0;
- IEN1 |= IEN1_DMAIE;
- }
-
- return id;
-}
-
-void
-ao_dma_set_transfer(uint8_t id,
- void __xdata *srcaddr,
- void __xdata *dstaddr,
- uint16_t count,
- uint8_t cfg0,
- uint8_t cfg1)
-{
- if (DMAARM & (1 << id))
- ao_panic(AO_PANIC_DMA);
- ao_dma_config[id].src_high = ((uint16_t) srcaddr) >> 8;
- ao_dma_config[id].src_low = ((uint16_t) srcaddr);
- ao_dma_config[id].dst_high = ((uint16_t) dstaddr) >> 8;
- ao_dma_config[id].dst_low = ((uint16_t) dstaddr);
- ao_dma_config[id].len_high = count >> 8;
- ao_dma_config[id].len_low = count;
- ao_dma_config[id].cfg0 = cfg0;
- ao_dma_config[id].cfg1 = cfg1 | DMA_CFG1_IRQMASK;
- if (id == 0) {
- DMA0CFGH = ((uint16_t) (&ao_dma_config[0])) >> 8;
- DMA0CFGL = ((uint16_t) (&ao_dma_config[0]));
- } else {
- DMA1CFGH = ((uint16_t) (&ao_dma_config[1])) >> 8;
- DMA1CFGL = ((uint16_t) (&ao_dma_config[1]));
- }
-}
-
-#define nop() _asm nop _endasm;
-
-void
-ao_dma_start(uint8_t id)
-{
- uint8_t mask = (1 << id);
- DMAIRQ &= ~mask;
- DMAARM = 0x80 | mask;
- nop(); nop(); nop(); nop();
- nop(); nop(); nop(); nop();
- *(ao_dma_done[id]) = 0;
- DMAARM = mask;
- nop(); nop(); nop(); nop();
- nop(); nop(); nop(); nop();
- nop();
-}
-
-void
-ao_dma_trigger(uint8_t id)
-{
- DMAREQ |= (1 << id);
-}
-
-void
-ao_dma_abort(uint8_t id)
-{
- uint8_t mask = (1 << id);
- DMAARM = 0x80 | mask;
- DMAIRQ &= ~mask;
-}
-
-void
-ao_dma_isr(void) __interrupt 8
-{
- uint8_t id, mask;
-
- /* Find the first DMA channel which is done */
- mask = 1;
- for (id = 0; id < ao_next_dma; id++) {
- if (DMAIRQ & mask) {
- /* Clear CPU interrupt flag */
- DMAIF = 0;
- /* Clear the completed ID */
- DMAIRQ = ~mask;
- *(ao_dma_done[id]) = 1;
- ao_wakeup(ao_dma_done[id]);
- break;
- }
- mask <<= 1;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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 "25lc1024.h"
-
-#define EE_BLOCK_SIZE ((uint16_t) (256))
-#define EE_BLOCK_SHIFT 8
-#define EE_DEVICE_SIZE ((uint32_t) 128 * (uint32_t) 1024)
-
-/* Total bytes of available storage */
-__pdata uint32_t ao_storage_total;
-
-/* Block size - device is erased in these units. At least 256 bytes */
-__pdata uint32_t ao_storage_block;
-
-/* Byte offset of config block. Will be ao_storage_block bytes long */
-__pdata uint32_t ao_storage_config;
-
-/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */
-__pdata uint16_t ao_storage_unit;
-
-/*
- * Using SPI on USART 0, with P1_2 as the chip select
- */
-
-#define EE_CS P1_2
-#define EE_CS_INDEX 2
-
-static __xdata uint8_t ao_ee_mutex;
-
-#define ao_ee_delay() do { \
- _asm nop _endasm; \
- _asm nop _endasm; \
- _asm nop _endasm; \
-} while(0)
-
-#define ao_ee_cs_low() ao_spi_get_bit(EE_CS)
-
-#define ao_ee_cs_high() ao_spi_put_bit(EE_CS)
-
-struct ao_ee_instruction {
- uint8_t instruction;
- uint8_t address[3];
-} __xdata ao_ee_instruction;
-
-static void
-ao_ee_write_enable(void)
-{
- ao_ee_cs_low();
- ao_ee_instruction.instruction = EE_WREN;
- ao_spi_send(&ao_ee_instruction, 1);
- ao_ee_cs_high();
-}
-
-static uint8_t
-ao_ee_rdsr(void)
-{
- ao_ee_cs_low();
- ao_ee_instruction.instruction = EE_RDSR;
- ao_spi_send(&ao_ee_instruction, 1);
- ao_spi_recv(&ao_ee_instruction, 1);
- ao_ee_cs_high();
- return ao_ee_instruction.instruction;
-}
-
-static void
-ao_ee_wrsr(uint8_t status)
-{
- ao_ee_cs_low();
- ao_ee_instruction.instruction = EE_WRSR;
- ao_ee_instruction.address[0] = status;
- ao_spi_send(&ao_ee_instruction, 2);
- ao_ee_cs_high();
-}
-
-#define EE_BLOCK_NONE 0xffff
-
-static __xdata uint8_t ao_ee_data[EE_BLOCK_SIZE];
-static __pdata uint16_t ao_ee_block = EE_BLOCK_NONE;
-static __pdata uint8_t ao_ee_block_dirty;
-
-/* Write the current block to the EEPROM */
-static void
-ao_ee_write_block(void)
-{
- uint8_t status;
-
- status = ao_ee_rdsr();
- if (status & (EE_STATUS_BP0|EE_STATUS_BP1|EE_STATUS_WPEN)) {
- status &= ~(EE_STATUS_BP0|EE_STATUS_BP1|EE_STATUS_WPEN);
- ao_ee_wrsr(status);
- }
- ao_ee_write_enable();
- ao_ee_cs_low();
- ao_ee_instruction.instruction = EE_WRITE;
- ao_ee_instruction.address[0] = ao_ee_block >> 8;
- ao_ee_instruction.address[1] = ao_ee_block;
- ao_ee_instruction.address[2] = 0;
- ao_spi_send(&ao_ee_instruction, 4);
- ao_spi_send(ao_ee_data, EE_BLOCK_SIZE);
- ao_ee_cs_high();
- for (;;) {
- uint8_t status = ao_ee_rdsr();
- if ((status & EE_STATUS_WIP) == 0)
- break;
- }
-}
-
-/* Read the current block from the EEPROM */
-static void
-ao_ee_read_block(void)
-{
- ao_ee_cs_low();
- ao_ee_instruction.instruction = EE_READ;
- ao_ee_instruction.address[0] = ao_ee_block >> 8;
- ao_ee_instruction.address[1] = ao_ee_block;
- ao_ee_instruction.address[2] = 0;
- ao_spi_send(&ao_ee_instruction, 4);
- ao_spi_recv(ao_ee_data, EE_BLOCK_SIZE);
- ao_ee_cs_high();
-}
-
-static void
-ao_ee_flush_internal(void)
-{
- if (ao_ee_block_dirty) {
- ao_ee_write_block();
- ao_ee_block_dirty = 0;
- }
-}
-
-static void
-ao_ee_fill(uint16_t block)
-{
- if (block != ao_ee_block) {
- ao_ee_flush_internal();
- ao_ee_block = block;
- ao_ee_read_block();
- }
-}
-
-uint8_t
-ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
-{
- uint16_t block = (uint16_t) (pos >> EE_BLOCK_SHIFT);
-
- /* Transfer the data */
- ao_mutex_get(&ao_ee_mutex); {
- if (len != EE_BLOCK_SIZE)
- ao_ee_fill(block);
- else {
- ao_ee_flush_internal();
- ao_ee_block = block;
- }
- memcpy(ao_ee_data + (uint16_t) (pos & 0xff), buf, len);
- ao_ee_block_dirty = 1;
- } ao_mutex_put(&ao_ee_mutex);
- return 1;
-}
-
-uint8_t
-ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
-{
- uint16_t block = (uint16_t) (pos >> EE_BLOCK_SHIFT);
-
- /* Transfer the data */
- ao_mutex_get(&ao_ee_mutex); {
- ao_ee_fill(block);
- memcpy(buf, ao_ee_data + (uint16_t) (pos & 0xff), len);
- } ao_mutex_put(&ao_ee_mutex);
- return 1;
-}
-
-void
-ao_storage_flush(void) __reentrant
-{
- ao_mutex_get(&ao_ee_mutex); {
- ao_ee_flush_internal();
- } ao_mutex_put(&ao_ee_mutex);
-}
-
-uint8_t
-ao_storage_erase(uint32_t pos) __reentrant
-{
- ao_mutex_get(&ao_ee_mutex); {
- ao_ee_flush_internal();
- ao_ee_block = (uint16_t) (pos >> EE_BLOCK_SHIFT);
- memset(ao_ee_data, 0xff, EE_BLOCK_SIZE);
- ao_ee_block_dirty = 1;
- } ao_mutex_put(&ao_ee_mutex);
- return 1;
-}
-
-static void
-ee_store(void) __reentrant
-{
-}
-
-void
-ao_storage_setup(void)
-{
- if (ao_storage_total == 0) {
- ao_storage_total = EE_DEVICE_SIZE;
- ao_storage_block = EE_BLOCK_SIZE;
- ao_storage_config = EE_DEVICE_SIZE - EE_BLOCK_SIZE;
- ao_storage_unit = EE_BLOCK_SIZE;
- }
-}
-
-void
-ao_storage_device_info(void) __reentrant
-{
-}
-
-/*
- * To initialize the chip, set up the CS line and
- * the SPI interface
- */
-void
-ao_storage_device_init(void)
-{
- /* set up CS */
- EE_CS = 1;
- P1DIR |= (1 << EE_CS_INDEX);
- P1SEL &= ~(1 << EE_CS_INDEX);
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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"
-
-/*
- * For hardware without eeprom, the config code still
- * wants to call these functions
- */
-uint8_t
-ao_ee_write_config(uint8_t *buf, uint16_t len) __reentrant
-{
- (void) buf;
- (void) len;
- return 1;
-}
-
-uint8_t
-ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant
-{
- memset(buf, '\0', len);
- return 1;
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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 "at45db161d.h"
-
-/* Total bytes of available storage */
-__pdata uint32_t ao_storage_total;
-
-/* Block size - device is erased in these units. At least 256 bytes */
-__pdata uint32_t ao_storage_block;
-
-/* Byte offset of config block. Will be ao_storage_block bytes long */
-__pdata uint32_t ao_storage_config;
-
-/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */
-__pdata uint16_t ao_storage_unit;
-
-#define FLASH_CS P1_1
-#define FLASH_CS_INDEX 1
-
-#define FLASH_BLOCK_SIZE_MAX 512
-
-__xdata uint8_t ao_flash_mutex;
-
-#define ao_flash_delay() do { \
- _asm nop _endasm; \
- _asm nop _endasm; \
- _asm nop _endasm; \
-} while(0)
-
-#define ao_flash_cs_low() ao_spi_get_bit(FLASH_CS)
-
-#define ao_flash_cs_high() ao_spi_put_bit(FLASH_CS)
-
-struct ao_flash_instruction {
- uint8_t instruction;
- uint8_t address[3];
-} __xdata ao_flash_instruction;
-
-static void
-ao_flash_set_pagesize_512(void)
-{
- ao_flash_cs_low();
- ao_flash_instruction.instruction = FLASH_SET_CONFIG;
- ao_flash_instruction.address[0] = FLASH_SET_512_BYTE_0;
- ao_flash_instruction.address[1] = FLASH_SET_512_BYTE_1;
- ao_flash_instruction.address[2] = FLASH_SET_512_BYTE_2;
- ao_spi_send(&ao_flash_instruction, 4);
- ao_flash_cs_high();
-}
-
-
-static uint8_t
-ao_flash_read_status(void)
-{
- ao_flash_cs_low();
- ao_flash_instruction.instruction = FLASH_READ_STATUS;
- ao_spi_send(&ao_flash_instruction, 1);
- ao_spi_recv(&ao_flash_instruction, 1);
- ao_flash_cs_high();
- return ao_flash_instruction.instruction;
-}
-
-#define FLASH_BLOCK_NONE 0xffff
-
-static __xdata uint8_t ao_flash_data[FLASH_BLOCK_SIZE_MAX];
-static __pdata uint16_t ao_flash_block = FLASH_BLOCK_NONE;
-static __pdata uint8_t ao_flash_block_dirty;
-static __pdata uint8_t ao_flash_write_pending;
-static __pdata uint8_t ao_flash_setup_done;
-static __pdata uint8_t ao_flash_block_shift;
-static __pdata uint16_t ao_flash_block_size;
-static __pdata uint16_t ao_flash_block_mask;
-
-void
-ao_storage_setup(void) __reentrant
-{
- uint8_t status;
-
- if (ao_flash_setup_done)
- return;
-
- ao_mutex_get(&ao_flash_mutex);
- if (ao_flash_setup_done) {
- ao_mutex_put(&ao_flash_mutex);
- return;
- }
-
- /* On first use, check to see if the flash chip has
- * been programmed to use 512 byte pages. If not, do so.
- * And then, because the flash part must be power cycled
- * for that change to take effect, panic.
- */
- status = ao_flash_read_status();
-
- if (!(status & FLASH_STATUS_PAGESIZE_512)) {
- ao_flash_set_pagesize_512();
- ao_panic(AO_PANIC_FLASH);
- }
-
- switch (status & 0x3c) {
-
- /* AT45DB321D */
- case 0x34:
- ao_flash_block_shift = 9;
- ao_storage_total = ((uint32_t) 4 * (uint32_t) 1024 * (uint32_t) 1024);
- break;
-
- /* AT45DB161D */
- case 0x2c:
- ao_flash_block_shift = 9;
- ao_storage_total = ((uint32_t) 2 * (uint32_t) 1024 * (uint32_t) 1024);
- break;
-
- /* AT45DB081D */
- case 0x24:
- ao_flash_block_shift = 8;
- ao_storage_total = ((uint32_t) 1024 * (uint32_t) 1024);
- break;
-
- /* AT45DB041D */
- case 0x1c:
- ao_flash_block_shift = 8;
- ao_storage_total = ((uint32_t) 512 * (uint32_t) 1024);
- break;
-
- /* AT45DB021D */
- case 0x14:
- ao_flash_block_shift = 8;
- ao_storage_total = ((uint32_t) 256 * (uint32_t) 1024);
- break;
-
- /* AT45DB011D */
- case 0x0c:
- ao_flash_block_shift = 8;
- ao_storage_total = ((uint32_t) 128 * (uint32_t) 1024);
- break;
-
- default:
- ao_panic(AO_PANIC_FLASH);
- }
- ao_flash_block_size = 1 << ao_flash_block_shift;
- ao_flash_block_mask = ao_flash_block_size - 1;
-
- ao_storage_block = ao_flash_block_size;
- ao_storage_config = ao_storage_total - ao_storage_block;
- ao_storage_unit = ao_flash_block_size;
-
- ao_flash_setup_done = 1;
- ao_mutex_put(&ao_flash_mutex);
-}
-
-static void
-ao_flash_wait_write(void)
-{
- if (ao_flash_write_pending) {
- for (;;) {
- uint8_t status = ao_flash_read_status();
- if ((status & FLASH_STATUS_RDY))
- break;
- }
- ao_flash_write_pending = 0;
- }
-}
-
-/* Write the current block to the FLASHPROM */
-static void
-ao_flash_write_block(void)
-{
- ao_flash_wait_write();
- ao_flash_cs_low();
- ao_flash_instruction.instruction = FLASH_WRITE;
-
- /* 13/14 block bits + 9/8 byte bits (always 0) */
- ao_flash_instruction.address[0] = ao_flash_block >> (16 - ao_flash_block_shift);
- ao_flash_instruction.address[1] = ao_flash_block << (ao_flash_block_shift - 8);
- ao_flash_instruction.address[2] = 0;
- ao_spi_send(&ao_flash_instruction, 4);
- ao_spi_send(ao_flash_data, ao_storage_block);
- ao_flash_cs_high();
- ao_flash_write_pending = 1;
-}
-
-/* Read the current block from the FLASHPROM */
-static void
-ao_flash_read_block(void)
-{
- ao_flash_wait_write();
- ao_flash_cs_low();
- ao_flash_instruction.instruction = FLASH_READ;
-
- /* 13/14 block bits + 9/8 byte bits (always 0) */
- ao_flash_instruction.address[0] = ao_flash_block >> (16 - ao_flash_block_shift);
- ao_flash_instruction.address[1] = ao_flash_block << (ao_flash_block_shift - 8);
- ao_flash_instruction.address[2] = 0;
- ao_spi_send(&ao_flash_instruction, 4);
- ao_spi_recv(ao_flash_data, ao_flash_block_size);
- ao_flash_cs_high();
-}
-
-static void
-ao_flash_flush_internal(void)
-{
- if (ao_flash_block_dirty) {
- ao_flash_write_block();
- ao_flash_block_dirty = 0;
- }
-}
-
-static void
-ao_flash_fill(uint16_t block)
-{
- if (block != ao_flash_block) {
- ao_flash_flush_internal();
- ao_flash_block = block;
- ao_flash_read_block();
- }
-}
-
-uint8_t
-ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
-{
- uint16_t block = (uint16_t) (pos >> ao_flash_block_shift);
-
- /* Transfer the data */
- ao_mutex_get(&ao_flash_mutex); {
- if (len != ao_flash_block_size)
- ao_flash_fill(block);
- else {
- ao_flash_flush_internal();
- ao_flash_block = block;
- }
- memcpy(ao_flash_data + (uint16_t) (pos & ao_flash_block_mask),
- buf,
- len);
- ao_flash_block_dirty = 1;
- } ao_mutex_put(&ao_flash_mutex);
- return 1;
-}
-
-uint8_t
-ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
-{
- uint16_t block = (uint16_t) (pos >> ao_flash_block_shift);
-
- /* Transfer the data */
- ao_mutex_get(&ao_flash_mutex); {
- ao_flash_fill(block);
- memcpy(buf,
- ao_flash_data + (uint16_t) (pos & ao_flash_block_mask),
- len);
- } ao_mutex_put(&ao_flash_mutex);
- return 1;
-}
-
-void
-ao_storage_flush(void) __reentrant
-{
- ao_mutex_get(&ao_flash_mutex); {
- ao_flash_flush_internal();
- } ao_mutex_put(&ao_flash_mutex);
-}
-
-uint8_t
-ao_storage_erase(uint32_t pos) __reentrant
-{
- ao_mutex_get(&ao_flash_mutex); {
- ao_flash_flush_internal();
- ao_flash_block = (uint16_t) (pos >> ao_flash_block_shift);
- memset(ao_flash_data, 0xff, ao_flash_block_size);
- ao_flash_block_dirty = 1;
- } ao_mutex_put(&ao_flash_mutex);
- return 1;
-}
-
-void
-ao_storage_device_info(void) __reentrant
-{
- uint8_t status;
-
- ao_storage_setup();
- ao_mutex_get(&ao_flash_mutex); {
- status = ao_flash_read_status();
- printf ("Flash status: 0x%02x\n", status);
- printf ("Flash block shift: %d\n", ao_flash_block_shift);
- printf ("Flash block size: %d\n", ao_flash_block_size);
- printf ("Flash block mask: %d\n", ao_flash_block_mask);
- printf ("Flash device size: %ld\n", ao_storage_total);
- } ao_mutex_put(&ao_flash_mutex);
-}
-
-/*
- * To initialize the chip, set up the CS line and
- * the SPI interface
- */
-void
-ao_storage_device_init(void)
-{
- /* set up CS */
- FLASH_CS = 1;
- P1DIR |= (1 << FLASH_CS_INDEX);
- P1SEL &= ~(1 << FLASH_CS_INDEX);
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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_FLIGHT_TEST
-#include "ao.h"
-#endif
-
-#ifndef HAS_ACCEL
-#error Please define HAS_ACCEL
-#endif
-
-#ifndef HAS_GPS
-#error Please define HAS_GPS
-#endif
-
-#ifndef HAS_USB
-#error Please define HAS_USB
-#endif
-
-/* Main flight thread. */
-
-__pdata enum ao_flight_state ao_flight_state; /* current flight state */
-__pdata uint16_t ao_launch_tick; /* time of launch detect */
-
-/*
- * track min/max data over a long interval to detect
- * resting
- */
-__pdata uint16_t ao_interval_end;
-__pdata int16_t ao_interval_min_height;
-__pdata int16_t ao_interval_max_height;
-__pdata uint8_t ao_flight_force_idle;
-
-/* We also have a clock, which can be used to sanity check things in
- * case of other failures
- */
-
-#define BOOST_TICKS_MAX AO_SEC_TO_TICKS(15)
-
-/* Landing is detected by getting constant readings from both pressure and accelerometer
- * for a fairly long time (AO_INTERVAL_TICKS)
- */
-#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(10)
-
-#define abs(a) ((a) < 0 ? -(a) : (a))
-
-void
-ao_flight(void)
-{
- ao_sample_init();
- ao_flight_state = ao_flight_startup;
- for (;;) {
-
- /*
- * Process ADC samples, just looping
- * until the sensors are calibrated.
- */
- if (!ao_sample())
- continue;
-
- switch (ao_flight_state) {
- case ao_flight_startup:
-
- /* Check to see what mode we should go to.
- * - Invalid mode if accel cal appears to be out
- * - pad mode if we're upright,
- * - idle mode otherwise
- */
-#if HAS_ACCEL
- if (ao_config.accel_plus_g == 0 ||
- ao_config.accel_minus_g == 0 ||
- ao_ground_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP ||
- ao_ground_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP)
- {
- /* Detected an accel value outside -1.5g to 1.5g
- * (or uncalibrated values), so we go into invalid mode
- */
- ao_flight_state = ao_flight_invalid;
-
- /* Turn on packet system in invalid mode on TeleMetrum */
- ao_packet_slave_start();
- } else
-#endif
- if (!ao_flight_force_idle
-#if HAS_ACCEL
- && ao_ground_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP
-#endif
- )
- {
- /* Set pad mode - we can fly! */
- ao_flight_state = ao_flight_pad;
-#if HAS_USB
- /* Disable the USB controller in flight mode
- * to save power
- */
- ao_usb_disable();
-#endif
-
-#if !HAS_ACCEL
- /* Disable packet mode in pad state on TeleMini */
- ao_packet_slave_stop();
-#endif
-
- /* Turn on telemetry system */
- ao_rdf_set(1);
- ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD);
-
- /* signal successful initialization by turning off the LED */
- ao_led_off(AO_LED_RED);
- } else {
- /* Set idle mode */
- ao_flight_state = ao_flight_idle;
-
-#if HAS_ACCEL
- /* Turn on packet system in idle mode on TeleMetrum */
- ao_packet_slave_start();
-#endif
-
- /* signal successful initialization by turning off the LED */
- ao_led_off(AO_LED_RED);
- }
- /* wakeup threads due to state change */
- ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
-
- break;
- case ao_flight_pad:
-
- /* pad to boost:
- *
- * barometer: > 20m vertical motion
- * OR
- * accelerometer: > 2g AND velocity > 5m/s
- *
- * The accelerometer should always detect motion before
- * the barometer, but we use both to make sure this
- * transition is detected. If the device
- * doesn't have an accelerometer, then ignore the
- * speed and acceleration as they are quite noisy
- * on the pad.
- */
- if (ao_height > AO_M_TO_HEIGHT(20)
-#if HAS_ACCEL
- || (ao_accel > AO_MSS_TO_ACCEL(20) &&
- ao_speed > AO_MS_TO_SPEED(5))
-#endif
- )
- {
- ao_flight_state = ao_flight_boost;
- ao_launch_tick = ao_sample_tick;
-
- /* start logging data */
- ao_log_start();
-
- /* Increase telemetry rate */
- ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_FLIGHT);
-
- /* disable RDF beacon */
- ao_rdf_set(0);
-
-#if HAS_GPS
- /* Record current GPS position by waking up GPS log tasks */
- ao_wakeup(&ao_gps_data);
- ao_wakeup(&ao_gps_tracking_data);
-#endif
-
- ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
- }
- break;
- case ao_flight_boost:
-
- /* boost to fast:
- *
- * accelerometer: start to fall at > 1/4 G
- * OR
- * time: boost for more than 15 seconds
- *
- * Detects motor burn out by the switch from acceleration to
- * deceleration, or by waiting until the maximum burn duration
- * (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)
- {
-#if HAS_ACCEL
- ao_flight_state = ao_flight_fast;
-#else
- ao_flight_state = ao_flight_coast;
-#endif
- ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
- }
- break;
-#if HAS_ACCEL
- case ao_flight_fast:
- /*
- * This is essentially the same as coast,
- * but the barometer is being ignored as
- * it may be unreliable.
- */
- if (ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED))
- {
- ao_flight_state = ao_flight_coast;
- ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
- }
- break;
-#endif
- case ao_flight_coast:
-
- /* apogee detect: coast to drogue deploy:
- *
- * speed: < 0
- *
- * Also make sure the model altitude is tracking
- * the measured altitude reasonably closely; otherwise
- * we're probably transsonic.
- */
- if (ao_speed < 0
-#if !HAS_ACCEL
- && (ao_sample_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 100)
-#endif
- )
- {
- /* ignite the drogue charge */
- ao_ignite(ao_igniter_drogue);
-
- /* slow down the telemetry system */
- ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER);
-
- /* Turn the RDF beacon back on */
- ao_rdf_set(1);
-
- /* and enter drogue state */
- ao_flight_state = ao_flight_drogue;
- ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
- }
-
- break;
- case ao_flight_drogue:
-
- /* drogue to main deploy:
- *
- * barometer: reach main deploy altitude
- *
- * Would like to use the accelerometer for this test, but
- * the orientation of the flight computer is unknown after
- * drogue deploy, so we ignore it. Could also detect
- * high descent rate using the pressure sensor to
- * recognize drogue deploy failure and eject the main
- * at that point. Perhaps also use the drogue sense lines
- * to notice continutity?
- */
- if (ao_height <= ao_config.main_deploy)
- {
- ao_ignite(ao_igniter_main);
-
- /*
- * Start recording min/max height
- * to figure out when the rocket has landed
- */
-
- /* initialize interval values */
- ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
-
- ao_interval_min_height = ao_interval_max_height = ao_avg_height;
-
- ao_flight_state = ao_flight_main;
- ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
- }
- break;
-
- /* fall through... */
- case ao_flight_main:
-
- /* main to land:
- *
- * barometer: altitude stable
- */
-
- if (ao_avg_height < ao_interval_min_height)
- ao_interval_min_height = ao_avg_height;
- if (ao_avg_height > ao_interval_max_height)
- ao_interval_max_height = ao_avg_height;
-
- if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) {
- if (ao_interval_max_height - ao_interval_min_height <= AO_M_TO_HEIGHT(4))
- {
- ao_flight_state = ao_flight_landed;
-
- /* turn off the ADC capture */
- ao_timer_set_adc_interval(0);
-
- ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
- }
- ao_interval_min_height = ao_interval_max_height = ao_avg_height;
- ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
- }
- break;
- case ao_flight_landed:
- break;
- }
- }
-}
-
-static __xdata struct ao_task flight_task;
-
-void
-ao_flight_init(void)
-{
- ao_flight_state = ao_flight_startup;
- ao_add_task(&flight_task, ao_flight, "flight");
-}
+++ /dev/null
-/*
- * 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"
-
-/* Main flight thread. */
-
-__pdata enum ao_flight_state ao_flight_state; /* current flight state */
-__pdata uint16_t ao_launch_tick; /* time of launch detect */
-
-/*
- * track min/max data over a long interval to detect
- * resting
- */
-__pdata uint16_t ao_interval_end;
-__pdata int16_t ao_interval_min_height;
-__pdata int16_t ao_interval_max_height;
-
-__pdata uint8_t ao_flight_force_idle;
-
-/* Landing is detected by getting constant readings from both pressure and accelerometer
- * for a fairly long time (AO_INTERVAL_TICKS)
- */
-#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(5)
-
-static void
-ao_flight_nano(void)
-{
- ao_sample_init();
- ao_flight_state = ao_flight_startup;
-
- for (;;) {
- /*
- * Process ADC samples, just looping
- * until the sensors are calibrated.
- */
- if (!ao_sample())
- continue;
-
- switch (ao_flight_state) {
- case ao_flight_startup:
- if (ao_flight_force_idle) {
- /* Set idle mode */
- ao_flight_state = ao_flight_idle;
- } else {
- ao_flight_state = ao_flight_pad;
- /* Disable packet mode in pad state */
- ao_packet_slave_stop();
-
- /* Turn on telemetry system */
- ao_rdf_set(1);
- ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD);
- }
- /* signal successful initialization by turning off the LED */
- ao_led_off(AO_LED_RED);
-
- /* wakeup threads due to state change */
- ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
- break;
- case ao_flight_pad:
- if (ao_height> AO_M_TO_HEIGHT(20)) {
- ao_flight_state = ao_flight_drogue;
- ao_launch_tick = ao_sample_tick;
-
- /* start logging data */
- ao_log_start();
-
- ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
- }
- break;
- case ao_flight_drogue:
- /* drogue/main to land:
- *
- * barometer: altitude stable
- */
-
- if (ao_height < ao_interval_min_height)
- ao_interval_min_height = ao_height;
- if (ao_height > ao_interval_max_height)
- ao_interval_max_height = ao_height;
-
- if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) {
- if (ao_interval_max_height - ao_interval_min_height < AO_M_TO_HEIGHT(5))
- {
- ao_flight_state = ao_flight_landed;
-
- /* turn off the ADC capture */
- ao_timer_set_adc_interval(0);
- ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
- }
- ao_interval_min_height = ao_interval_max_height = ao_height;
- ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
- }
- break;
- }
- }
-}
-
-static __xdata struct ao_task flight_task;
-
-void
-ao_flight_nano_init(void)
-{
- ao_flight_state = ao_flight_startup;
- ao_add_task(&flight_task, ao_flight_nano, "flight");
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#define _GNU_SOURCE
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <math.h>
-
-#define AO_HERTZ 100
-
-#define AO_ADC_RING 64
-#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1))
-#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1))
-
-#define AO_M_TO_HEIGHT(m) ((int16_t) (m))
-#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16))
-#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16))
-
-/*
- * One set of samples read from the A/D converter
- */
-struct ao_adc {
- uint16_t tick; /* tick when the sample was read */
- int16_t accel; /* accelerometer */
- int16_t pres; /* pressure sensor */
- int16_t pres_real; /* unclipped */
- 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 __pdata
-#define __data
-#define __xdata
-#define __code
-#define __reentrant
-
-#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5))
-#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5))
-#define from_fix(x) ((x) >> 16)
-
-/*
- * Above this height, the baro sensor doesn't work
- */
-#define AO_MAX_BARO_HEIGHT 12000
-#define AO_BARO_SATURATE 13000
-#define AO_MIN_BARO_VALUE ao_altitude_to_pres(AO_BARO_SATURATE)
-
-/*
- * Above this speed, baro measurements are unreliable
- */
-#define AO_MAX_BARO_SPEED 200
-
-#define ACCEL_NOSE_UP (ao_accel_2g >> 2)
-
-enum ao_flight_state {
- ao_flight_startup = 0,
- ao_flight_idle = 1,
- ao_flight_pad = 2,
- ao_flight_boost = 3,
- ao_flight_fast = 4,
- ao_flight_coast = 5,
- ao_flight_drogue = 6,
- ao_flight_main = 7,
- ao_flight_landed = 8,
- ao_flight_invalid = 9
-};
-
-extern enum ao_flight_state ao_flight_state;
-
-#define FALSE 0
-#define TRUE 1
-
-struct ao_adc ao_adc_ring[AO_ADC_RING];
-uint8_t ao_adc_head;
-int ao_summary = 0;
-
-#define ao_led_on(l)
-#define ao_led_off(l)
-#define ao_timer_set_adc_interval(i)
-#define ao_wakeup(wchan) ao_dump_state()
-#define ao_cmd_register(c)
-#define ao_usb_disable()
-#define ao_telemetry_set_interval(x)
-#define ao_rdf_set(rdf)
-#define ao_packet_slave_start()
-#define ao_packet_slave_stop()
-
-enum ao_igniter {
- ao_igniter_drogue = 0,
- ao_igniter_main = 1
-};
-
-struct ao_adc ao_adc_static;
-
-int drogue_height;
-double drogue_time;
-int main_height;
-double main_time;
-
-int tick_offset;
-
-static int32_t ao_k_height;
-
-void
-ao_ignite(enum ao_igniter igniter)
-{
- double time = (double) (ao_adc_static.tick + tick_offset) / 100;
-
- if (igniter == ao_igniter_drogue) {
- drogue_time = time;
- drogue_height = ao_k_height >> 16;
- } else {
- main_time = time;
- main_height = ao_k_height >> 16;
- }
-}
-
-struct ao_task {
- int dummy;
-};
-
-#define ao_add_task(t,f,n)
-
-#define ao_log_start()
-#define ao_log_stop()
-
-#define AO_MS_TO_TICKS(ms) ((ms) / 10)
-#define AO_SEC_TO_TICKS(s) ((s) * 100)
-
-#define AO_FLIGHT_TEST
-
-int ao_flight_debug;
-
-FILE *emulator_in;
-char *emulator_app;
-char *emulator_name;
-double emulator_error_max = 4;
-double emulator_height_error_max = 20; /* noise in the baro sensor */
-
-void
-ao_dump_state(void);
-
-void
-ao_sleep(void *wchan);
-
-const char const * const ao_state_names[] = {
- "startup", "idle", "pad", "boost", "fast",
- "coast", "drogue", "main", "landed", "invalid"
-};
-
-struct ao_cmds {
- void (*func)(void);
- const char *help;
-};
-
-#include "ao_convert.c"
-
-struct ao_config {
- uint16_t main_deploy;
- int16_t accel_plus_g;
- int16_t accel_minus_g;
- uint8_t pad_orientation;
-};
-
-#define AO_PAD_ORIENTATION_ANTENNA_UP 0
-#define AO_PAD_ORIENTATION_ANTENNA_DOWN 1
-
-#define ao_config_get()
-
-struct ao_config ao_config;
-
-#define DATA_TO_XDATA(x) (x)
-
-#define HAS_FLIGHT 1
-#define HAS_ADC 1
-#define HAS_USB 1
-#define HAS_GPS 1
-#ifndef HAS_ACCEL
-#define HAS_ACCEL 1
-#define HAS_ACCEL_REF 0
-#endif
-
-#define GRAVITY 9.80665
-extern int16_t ao_ground_accel, ao_flight_accel;
-extern int16_t ao_accel_2g;
-
-extern uint16_t ao_sample_tick;
-
-extern int16_t ao_sample_height;
-extern int16_t ao_sample_accel;
-extern int32_t ao_accel_scale;
-extern int16_t ao_ground_height;
-extern int16_t ao_sample_alt;
-
-int ao_sample_prev_tick;
-uint16_t prev_tick;
-
-#include "ao_kalman.c"
-#include "ao_sample.c"
-#include "ao_flight.c"
-
-#define to_double(f) ((f) / 65536.0)
-
-static int ao_records_read = 0;
-static int ao_eof_read = 0;
-static int ao_flight_ground_accel;
-static int ao_flight_started = 0;
-static int ao_test_max_height;
-static double ao_test_max_height_time;
-static int ao_test_main_height;
-static double ao_test_main_height_time;
-static double ao_test_landed_time;
-static double ao_test_landed_height;
-static double ao_test_landed_time;
-static int landed_set;
-static double landed_time;
-static double landed_height;
-
-void
-ao_test_exit(void)
-{
- double drogue_error;
- double main_error;
- double landed_error;
- double landed_time_error;
-
- if (!ao_test_main_height_time) {
- ao_test_main_height_time = ao_test_max_height_time;
- ao_test_main_height = ao_test_max_height;
- }
- drogue_error = fabs(ao_test_max_height_time - drogue_time);
- main_error = fabs(ao_test_main_height_time - main_time);
- landed_error = fabs(ao_test_landed_height - landed_height);
- landed_time_error = ao_test_landed_time - landed_time;
- if (drogue_error > emulator_error_max || main_error > emulator_error_max ||
- landed_time_error > emulator_error_max || landed_error > emulator_height_error_max) {
- printf ("%s %s\n",
- emulator_app, emulator_name);
- printf ("\tApogee error %g\n", drogue_error);
- printf ("\tMain error %g\n", main_error);
- printf ("\tLanded height error %g\n", landed_error);
- printf ("\tLanded time error %g\n", landed_time_error);
- printf ("\tActual: apogee: %d at %7.2f main: %d at %7.2f landed %7.2f at %7.2f\n",
- ao_test_max_height, ao_test_max_height_time,
- ao_test_main_height, ao_test_main_height_time,
- ao_test_landed_height, ao_test_landed_time);
- printf ("\tComputed: apogee: %d at %7.2f main: %d at %7.2f landed %7.2f at %7.2f\n",
- drogue_height, drogue_time, main_height, main_time,
- landed_height, landed_time);
- exit (1);
- }
- exit(0);
-}
-
-void
-ao_insert(void)
-{
- double time;
-
- ao_adc_ring[ao_adc_head] = ao_adc_static;
- ao_adc_head = ao_adc_ring_next(ao_adc_head);
- if (ao_flight_state != ao_flight_startup) {
- double height = ao_pres_to_altitude(ao_adc_static.pres_real) - ao_ground_height;
- double accel = ((ao_flight_ground_accel - ao_adc_static.accel) * GRAVITY * 2.0) /
- (ao_config.accel_minus_g - ao_config.accel_plus_g);
-
- if (!tick_offset)
- tick_offset = -ao_adc_static.tick;
- if ((prev_tick - ao_adc_static.tick) > 0x400)
- tick_offset += 65536;
- prev_tick = ao_adc_static.tick;
- time = (double) (ao_adc_static.tick + tick_offset) / 100;
-
- if (ao_test_max_height < height) {
- ao_test_max_height = height;
- ao_test_max_height_time = time;
- ao_test_landed_height = height;
- ao_test_landed_time = time;
- }
- if (height > ao_config.main_deploy) {
- ao_test_main_height_time = time;
- ao_test_main_height = height;
- }
-
- if (ao_test_landed_height > height) {
- ao_test_landed_height = height;
- ao_test_landed_time = time;
- }
-
- if (ao_flight_state == ao_flight_landed && !landed_set) {
- landed_set = 1;
- landed_time = time;
- landed_height = height;
- }
-
- if (!ao_summary) {
- printf("%7.2f height %8.2f accel %8.3f state %-8.8s k_height %8.2f k_speed %8.3f k_accel %8.3f avg_height %5d drogue %4d main %4d error %5d\n",
- time,
- height,
- accel,
- ao_state_names[ao_flight_state],
- ao_k_height / 65536.0,
- ao_k_speed / 65536.0 / 16.0,
- ao_k_accel / 65536.0 / 16.0,
- ao_avg_height,
- drogue_height,
- main_height,
- ao_error_h_sq_avg);
-
-// if (ao_flight_state == ao_flight_landed)
-// ao_test_exit();
- }
- }
-}
-
-#define AO_MAX_CALLSIGN 8
-#define AO_MAX_VERSION 8
-#define AO_MAX_TELEMETRY 128
-
-struct ao_telemetry_generic {
- uint16_t serial; /* 0 */
- uint16_t tick; /* 2 */
- uint8_t type; /* 4 */
- uint8_t payload[27]; /* 5 */
- /* 32 */
-};
-
-#define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01
-#define AO_TELEMETRY_SENSOR_TELEMINI 0x02
-#define AO_TELEMETRY_SENSOR_TELENANO 0x03
-
-struct ao_telemetry_sensor {
- uint16_t serial; /* 0 */
- uint16_t tick; /* 2 */
- uint8_t type; /* 4 */
-
- uint8_t state; /* 5 flight state */
- int16_t accel; /* 6 accelerometer (TM only) */
- int16_t pres; /* 8 pressure sensor */
- int16_t temp; /* 10 temperature sensor */
- int16_t v_batt; /* 12 battery voltage */
- int16_t sense_d; /* 14 drogue continuity sense (TM/Tm) */
- int16_t sense_m; /* 16 main continuity sense (TM/Tm) */
-
- int16_t acceleration; /* 18 m/s² * 16 */
- int16_t speed; /* 20 m/s * 16 */
- int16_t height; /* 22 m */
-
- int16_t ground_pres; /* 24 average pres on pad */
- int16_t ground_accel; /* 26 average accel on pad */
- int16_t accel_plus_g; /* 28 accel calibration at +1g */
- int16_t accel_minus_g; /* 30 accel calibration at -1g */
- /* 32 */
-};
-
-#define AO_TELEMETRY_CONFIGURATION 0x04
-
-struct ao_telemetry_configuration {
- uint16_t serial; /* 0 */
- uint16_t tick; /* 2 */
- uint8_t type; /* 4 */
-
- uint8_t device; /* 5 device type */
- uint16_t flight; /* 6 flight number */
- uint8_t config_major; /* 8 Config major version */
- uint8_t config_minor; /* 9 Config minor version */
- uint16_t apogee_delay; /* 10 Apogee deploy delay in seconds */
- uint16_t main_deploy; /* 12 Main deploy alt in meters */
- uint16_t flight_log_max; /* 14 Maximum flight log size in kB */
- char callsign[AO_MAX_CALLSIGN]; /* 16 Radio operator identity */
- char version[AO_MAX_VERSION]; /* 24 Software version */
- /* 32 */
-};
-
-#define AO_TELEMETRY_LOCATION 0x05
-
-#define AO_GPS_MODE_NOT_VALID 'N'
-#define AO_GPS_MODE_AUTONOMOUS 'A'
-#define AO_GPS_MODE_DIFFERENTIAL 'D'
-#define AO_GPS_MODE_ESTIMATED 'E'
-#define AO_GPS_MODE_MANUAL 'M'
-#define AO_GPS_MODE_SIMULATED 'S'
-
-struct ao_telemetry_location {
- uint16_t serial; /* 0 */
- uint16_t tick; /* 2 */
- uint8_t type; /* 4 */
-
- uint8_t flags; /* 5 Number of sats and other flags */
- int16_t altitude; /* 6 GPS reported altitude (m) */
- int32_t latitude; /* 8 latitude (degrees * 10⁷) */
- int32_t longitude; /* 12 longitude (degrees * 10⁷) */
- uint8_t year; /* 16 (- 2000) */
- uint8_t month; /* 17 (1-12) */
- uint8_t day; /* 18 (1-31) */
- uint8_t hour; /* 19 (0-23) */
- uint8_t minute; /* 20 (0-59) */
- uint8_t second; /* 21 (0-59) */
- uint8_t pdop; /* 22 (m * 5) */
- uint8_t hdop; /* 23 (m * 5) */
- uint8_t vdop; /* 24 (m * 5) */
- uint8_t mode; /* 25 */
- uint16_t ground_speed; /* 26 cm/s */
- int16_t climb_rate; /* 28 cm/s */
- uint8_t course; /* 30 degrees / 2 */
- uint8_t unused[1]; /* 31 */
- /* 32 */
-};
-
-#define AO_TELEMETRY_SATELLITE 0x06
-
-struct ao_telemetry_satellite_info {
- uint8_t svid;
- uint8_t c_n_1;
-};
-
-struct ao_telemetry_satellite {
- uint16_t serial; /* 0 */
- uint16_t tick; /* 2 */
- uint8_t type; /* 4 */
- uint8_t channels; /* 5 number of reported sats */
-
- struct ao_telemetry_satellite_info sats[12]; /* 6 */
- uint8_t unused[2]; /* 30 */
- /* 32 */
-};
-
-union ao_telemetry_all {
- struct ao_telemetry_generic generic;
- struct ao_telemetry_sensor sensor;
- struct ao_telemetry_configuration configuration;
- struct ao_telemetry_location location;
- struct ao_telemetry_satellite satellite;
-};
-
-uint16_t
-uint16(uint8_t *bytes, int off)
-{
- off++;
- return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8);
-}
-
-int16_t
-int16(uint8_t *bytes, int off)
-{
- return (int16_t) uint16(bytes, off);
-}
-
-void
-ao_sleep(void *wchan)
-{
- if (wchan == &ao_adc_head) {
- char type;
- uint16_t tick;
- uint16_t a, b;
- int ret;
- uint8_t bytes[1024];
- union ao_telemetry_all telem;
- char line[1024];
- char *saveptr;
- char *l;
- char *words[64];
- int nword;
-
- for (;;) {
- if (ao_records_read > 2 && ao_flight_state == ao_flight_startup)
- {
- ao_adc_static.accel = ao_flight_ground_accel;
- ao_insert();
- return;
- }
-
- if (!fgets(line, sizeof (line), emulator_in)) {
- if (++ao_eof_read >= 1000) {
- if (!ao_summary)
- printf ("no more data, exiting simulation\n");
- ao_test_exit();
- }
- ao_adc_static.tick += 10;
- ao_insert();
- return;
- }
- l = line;
- for (nword = 0; nword < 64; nword++) {
- words[nword] = strtok_r(l, " \t\n", &saveptr);
- l = NULL;
- if (words[nword] == NULL)
- break;
- }
- if (nword == 4) {
- type = words[0][0];
- tick = strtoul(words[1], NULL, 16);
- a = strtoul(words[2], NULL, 16);
- b = strtoul(words[3], NULL, 16);
- if (type == 'P')
- type = 'A';
- } else if (nword >= 6 && strcmp(words[0], "Accel") == 0) {
- ao_config.accel_plus_g = atoi(words[3]);
- ao_config.accel_minus_g = atoi(words[5]);
- } else if (nword >= 4 && strcmp(words[0], "Main") == 0) {
- ao_config.main_deploy = atoi(words[2]);
- } else if (nword >= 36 && strcmp(words[0], "CALL") == 0) {
- tick = atoi(words[10]);
- if (!ao_flight_started) {
- type = 'F';
- a = atoi(words[26]);
- ao_flight_started = 1;
- } else {
- type = 'A';
- a = atoi(words[12]);
- b = atoi(words[14]);
- }
- } else if (nword == 3 && strcmp(words[0], "BARO") == 0) {
- tick = strtol(words[1], NULL, 16);
- a = 16384 - 328;
- b = strtol(words[2], NULL, 10);
- type = 'A';
- if (!ao_flight_started) {
- ao_flight_ground_accel = 16384 - 328;
- ao_config.accel_plus_g = 16384 - 328;
- ao_config.accel_minus_g = 16384 + 328;
- ao_flight_started = 1;
- }
- } else if (nword == 2 && strcmp(words[0], "TELEM") == 0) {
- char *hex = words[1];
- char elt[3];
- int i, len;
- uint8_t sum;
-
- len = strlen(hex);
- if (len > sizeof (bytes) * 2) {
- len = sizeof (bytes)*2;
- hex[len] = '\0';
- }
- for (i = 0; i < len; i += 2) {
- elt[0] = hex[i];
- elt[1] = hex[i+1];
- elt[2] = '\0';
- bytes[i/2] = (uint8_t) strtol(elt, NULL, 16);
- }
- len = i/2;
- if (bytes[0] != len - 2) {
- printf ("bad length %d != %d\n", bytes[0], len - 2);
- continue;
- }
- sum = 0x5a;
- for (i = 1; i < len-1; i++)
- sum += bytes[i];
- if (sum != bytes[len-1]) {
- printf ("bad checksum\n");
- continue;
- }
- if ((bytes[len-2] & 0x80) == 0) {
- continue;
- }
- if (len == 36) {
- memcpy(&telem, bytes + 1, 32);
- tick = telem.generic.tick;
- switch (telem.generic.type) {
- case AO_TELEMETRY_SENSOR_TELEMETRUM:
- case AO_TELEMETRY_SENSOR_TELEMINI:
- case AO_TELEMETRY_SENSOR_TELENANO:
- if (!ao_flight_started) {
- ao_flight_ground_accel = telem.sensor.ground_accel;
- ao_config.accel_plus_g = telem.sensor.accel_plus_g;
- ao_config.accel_minus_g = telem.sensor.accel_minus_g;
- ao_flight_started = 1;
- }
- type = 'A';
- a = telem.sensor.accel;
- b = telem.sensor.pres;
- break;
- }
- } else if (len == 99) {
- ao_flight_started = 1;
- tick = uint16(bytes, 21);
- ao_flight_ground_accel = int16(bytes, 7);
- ao_config.accel_plus_g = int16(bytes, 17);
- ao_config.accel_minus_g = int16(bytes, 19);
- type = 'A';
- a = int16(bytes, 23);
- b = int16(bytes, 25);
- } else if (len == 98) {
- ao_flight_started = 1;
- tick = uint16(bytes, 20);
- ao_flight_ground_accel = int16(bytes, 6);
- ao_config.accel_plus_g = int16(bytes, 16);
- ao_config.accel_minus_g = int16(bytes, 18);
- type = 'A';
- a = int16(bytes, 22);
- b = int16(bytes, 24);
- } else {
- printf("unknown len %d\n", len);
- continue;
- }
- }
- if (type != 'F' && !ao_flight_started)
- continue;
-
- switch (type) {
- case 'F':
- ao_flight_ground_accel = a;
- if (ao_config.accel_plus_g == 0) {
- ao_config.accel_plus_g = a;
- ao_config.accel_minus_g = a + 530;
- }
- if (ao_config.main_deploy == 0)
- ao_config.main_deploy = 250;
- ao_flight_started = 1;
- break;
- case 'S':
- break;
- case 'A':
- ao_adc_static.tick = tick;
- ao_adc_static.accel = a;
- ao_adc_static.pres_real = b;
- if (b < AO_MIN_BARO_VALUE)
- b = AO_MIN_BARO_VALUE;
- ao_adc_static.pres = b;
- ao_records_read++;
- ao_insert();
- return;
- case 'T':
- ao_adc_static.tick = tick;
- ao_adc_static.temp = a;
- ao_adc_static.v_batt = b;
- break;
- case 'D':
- case 'G':
- case 'N':
- case 'W':
- case 'H':
- break;
- }
- }
-
- }
-}
-#define COUNTS_PER_G 264.8
-
-void
-ao_dump_state(void)
-{
-}
-
-static const struct option options[] = {
- { .name = "summary", .has_arg = 0, .val = 's' },
- { .name = "debug", .has_arg = 0, .val = 'd' },
- { 0, 0, 0, 0},
-};
-
-void run_flight_fixed(char *name, FILE *f, int summary)
-{
- emulator_name = name;
- emulator_in = f;
- ao_summary = summary;
- ao_flight_init();
- ao_flight();
-}
-
-int
-main (int argc, char **argv)
-{
- int summary = 0;
- int c;
- int i;
-
-#if HAS_ACCEL
- emulator_app="full";
-#else
- emulator_app="baro";
-#endif
- while ((c = getopt_long(argc, argv, "sd", options, NULL)) != -1) {
- switch (c) {
- case 's':
- summary = 1;
- break;
- case 'd':
- ao_flight_debug = 1;
- break;
- }
- }
-
- if (optind == argc)
- run_flight_fixed("<stdin>", stdin, summary);
- else
- for (i = optind; i < argc; i++) {
- FILE *f = fopen(argv[i], "r");
- if (!f) {
- perror(argv[i]);
- continue;
- }
- run_flight_fixed(argv[i], f, summary);
- fclose(f);
- }
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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_GPS_TEST
-#include "ao.h"
-#endif
-#include "ao_telem.h"
-
-void
-ao_gps_print(__xdata struct ao_gps_orig *gps_data) __reentrant
-{
- char state;
-
- if (gps_data->flags & AO_GPS_VALID)
- state = AO_TELEM_GPS_STATE_LOCKED;
- else if (gps_data->flags & AO_GPS_RUNNING)
- state = AO_TELEM_GPS_STATE_UNLOCKED;
- else
- state = AO_TELEM_GPS_STATE_ERROR;
- printf(AO_TELEM_GPS_STATE " %c "
- AO_TELEM_GPS_NUM_SAT " %d ",
- state,
- (gps_data->flags & AO_GPS_NUM_SAT_MASK) >> AO_GPS_NUM_SAT_SHIFT);
- if (!(gps_data->flags & AO_GPS_VALID))
- return;
- printf(AO_TELEM_GPS_LATITUDE " %ld "
- AO_TELEM_GPS_LONGITUDE " %ld "
- AO_TELEM_GPS_ALTITUDE " %d ",
- gps_data->latitude,
- gps_data->longitude,
- gps_data->altitude);
-
- if (gps_data->flags & AO_GPS_DATE_VALID)
- printf(AO_TELEM_GPS_YEAR " %d "
- AO_TELEM_GPS_MONTH " %d "
- AO_TELEM_GPS_DAY " %d ",
- gps_data->year,
- gps_data->month,
- gps_data->day);
-
- printf(AO_TELEM_GPS_HOUR " %d "
- AO_TELEM_GPS_MINUTE " %d "
- AO_TELEM_GPS_SECOND " %d ",
- gps_data->hour,
- gps_data->minute,
- gps_data->second);
-
- printf(AO_TELEM_GPS_HDOP " %d ",
- gps_data->hdop * 2);
-
- if (gps_data->flags & AO_GPS_COURSE_VALID) {
- printf(AO_TELEM_GPS_HERROR " %d "
- AO_TELEM_GPS_VERROR " %d "
- AO_TELEM_GPS_VERTICAL_SPEED " %d "
- AO_TELEM_GPS_HORIZONTAL_SPEED " %d "
- AO_TELEM_GPS_COURSE " %d ",
- gps_data->h_error,
- gps_data->v_error,
- gps_data->climb_rate,
- gps_data->ground_speed,
- (int) gps_data->course * 2);
- }
-}
-
-void
-ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data) __reentrant
-{
- uint8_t c, n, v;
- __xdata struct ao_gps_sat_orig *sat;
-
- n = gps_tracking_data->channels;
- if (n == 0)
- return;
-
- sat = gps_tracking_data->sats;
- v = 0;
- for (c = 0; c < n; c++) {
- if (sat->svid)
- v++;
- sat++;
- }
-
- printf (AO_TELEM_SAT_NUM " %d ",
- v);
-
- sat = gps_tracking_data->sats;
- v = 0;
- for (c = 0; c < n; c++) {
- if (sat->svid) {
- printf (AO_TELEM_SAT_SVID "%d %d "
- AO_TELEM_SAT_C_N_0 "%d %d ",
- v, sat->svid,
- v, sat->c_n_1);
- v++;
- }
- sat++;
- }
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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
-ao_gps_report(void)
-{
- static __xdata struct ao_log_record gps_log;
- static __xdata struct ao_telemetry_location gps_data;
- uint8_t date_reported = 0;
-
- for (;;) {
- ao_sleep(&ao_gps_data);
- ao_mutex_get(&ao_gps_mutex);
- memcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data));
- ao_mutex_put(&ao_gps_mutex);
-
- if (!(gps_data.flags & AO_GPS_VALID))
- continue;
-
- gps_log.tick = ao_gps_tick;
- gps_log.type = AO_LOG_GPS_TIME;
- gps_log.u.gps_time.hour = gps_data.hour;
- gps_log.u.gps_time.minute = gps_data.minute;
- gps_log.u.gps_time.second = gps_data.second;
- gps_log.u.gps_time.flags = gps_data.flags;
- ao_log_data(&gps_log);
- gps_log.type = AO_LOG_GPS_LAT;
- gps_log.u.gps_latitude = gps_data.latitude;
- ao_log_data(&gps_log);
- gps_log.type = AO_LOG_GPS_LON;
- gps_log.u.gps_longitude = gps_data.longitude;
- ao_log_data(&gps_log);
- gps_log.type = AO_LOG_GPS_ALT;
- gps_log.u.gps_altitude.altitude = gps_data.altitude;
- gps_log.u.gps_altitude.unused = 0xffff;
- ao_log_data(&gps_log);
- if (!date_reported && (gps_data.flags & AO_GPS_DATE_VALID)) {
- gps_log.type = AO_LOG_GPS_DATE;
- gps_log.u.gps_date.year = gps_data.year;
- gps_log.u.gps_date.month = gps_data.month;
- gps_log.u.gps_date.day = gps_data.day;
- gps_log.u.gps_date.extra = 0;
- date_reported = ao_log_data(&gps_log);
- }
- }
-}
-
-void
-ao_gps_tracking_report(void)
-{
- static __xdata struct ao_log_record gps_log;
- static __xdata struct ao_telemetry_satellite gps_tracking_data;
- uint8_t c, n;
-
- for (;;) {
- ao_sleep(&ao_gps_tracking_data);
- ao_mutex_get(&ao_gps_mutex);
- gps_log.tick = ao_gps_tick;
- memcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data));
- ao_mutex_put(&ao_gps_mutex);
-
- if (!(n = gps_tracking_data.channels))
- continue;
-
- gps_log.type = AO_LOG_GPS_SAT;
- for (c = 0; c < n; c++)
- if ((gps_log.u.gps_sat.svid = gps_tracking_data.sats[c].svid))
- {
- gps_log.u.gps_sat.c_n = gps_tracking_data.sats[c].c_n_1;
- ao_log_data(&gps_log);
- }
- }
-}
-
-__xdata struct ao_task ao_gps_report_task;
-__xdata struct ao_task ao_gps_tracking_report_task;
-
-void
-ao_gps_report_init(void)
-{
- ao_add_task(&ao_gps_report_task, ao_gps_report, "gps_report");
- ao_add_task(&ao_gps_tracking_report_task, ao_gps_tracking_report, "gps_tracking_report");
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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_GPS_TEST
-#include "ao.h"
-#endif
-
-__xdata uint8_t ao_gps_mutex;
-__pdata uint16_t ao_gps_tick;
-__xdata struct ao_telemetry_location ao_gps_data;
-__xdata struct ao_telemetry_satellite ao_gps_tracking_data;
-
-static const char ao_gps_set_nmea[] = "\r\n$PSRF100,0,57600,8,1,0*37\r\n";
-
-const char ao_gps_config[] = {
-
- 0xa0, 0xa2, 0x00, 0x0e, /* length: 14 bytes */
- 136, /* mode control */
- 0, 0, /* reserved */
- 0, /* degraded mode (allow 1-SV navigation) */
- 0, 0, /* reserved */
- 0, 0, /* user specified altitude */
- 2, /* alt hold mode (disabled, require 3d fixes) */
- 0, /* alt hold source (use last computed altitude) */
- 0, /* reserved */
- 10, /* Degraded time out (10 sec) */
- 10, /* Dead Reckoning time out (10 sec) */
- 0, /* Track smoothing (disabled) */
- 0x00, 0x8e, 0xb0, 0xb3,
-
- 0xa0, 0xa2, 0x00, 0x08, /* length: 8 bytes */
- 166, /* Set message rate */
- 2, /* enable/disable all messages */
- 0, /* message id (ignored) */
- 0, /* update rate (0 = disable) */
- 0, 0, 0, 0, /* reserved */
- 0x00, 0xa8, 0xb0, 0xb3,
-
- 0xa0, 0xa2, 0x00, 0x02, /* length: 2 bytes */
- 143, /* static navigation */
- 0, /* disable */
- 0x00, 0x8f, 0xb0, 0xb3,
-};
-
-#define NAV_TYPE_GPS_FIX_TYPE_MASK (7 << 0)
-#define NAV_TYPE_NO_FIX (0 << 0)
-#define NAV_TYPE_SV_KF (1 << 0)
-#define NAV_TYPE_2_SV_KF (2 << 0)
-#define NAV_TYPE_3_SV_KF (3 << 0)
-#define NAV_TYPE_4_SV_KF (4 << 0)
-#define NAV_TYPE_2D_LEAST_SQUARES (5 << 0)
-#define NAV_TYPE_3D_LEAST_SQUARES (6 << 0)
-#define NAV_TYPE_DR (7 << 0)
-#define NAV_TYPE_TRICKLE_POWER (1 << 3)
-#define NAV_TYPE_ALTITUDE_HOLD_MASK (3 << 4)
-#define NAV_TYPE_ALTITUDE_HOLD_NONE (0 << 4)
-#define NAV_TYPE_ALTITUDE_HOLD_KF (1 << 4)
-#define NAV_TYPE_ALTITUDE_HOLD_USER (2 << 4)
-#define NAV_TYPE_ALTITUDE_HOLD_ALWAYS (3 << 4)
-#define NAV_TYPE_DOP_LIMIT_EXCEEDED (1 << 6)
-#define NAV_TYPE_DGPS_APPLIED (1 << 7)
-#define NAV_TYPE_SENSOR_DR (1 << 8)
-#define NAV_TYPE_OVERDETERMINED (1 << 9)
-#define NAV_TYPE_DR_TIMEOUT_EXCEEDED (1 << 10)
-#define NAV_TYPE_FIX_MI_EDIT (1 << 11)
-#define NAV_TYPE_INVALID_VELOCITY (1 << 12)
-#define NAV_TYPE_ALTITUDE_HOLD_DISABLED (1 << 13)
-#define NAV_TYPE_DR_ERROR_STATUS_MASK (3 << 14)
-#define NAV_TYPE_DR_ERROR_STATUS_GPS_ONLY (0 << 14)
-#define NAV_TYPE_DR_ERROR_STATUS_DR_FROM_GPS (1 << 14)
-#define NAV_TYPE_DR_ERROR_STATUS_DR_SENSOR_ERROR (2 << 14)
-#define NAV_TYPE_DR_ERROR_STATUS_DR_IN_TEST (3 << 14)
-
-struct sirf_geodetic_nav_data {
- uint16_t nav_type;
- uint16_t utc_year;
- uint8_t utc_month;
- uint8_t utc_day;
- uint8_t utc_hour;
- uint8_t utc_minute;
- uint16_t utc_second;
- int32_t lat;
- int32_t lon;
- int32_t alt_msl;
- uint16_t ground_speed;
- uint16_t course;
- int16_t climb_rate;
- uint32_t h_error;
- uint32_t v_error;
- uint8_t num_sv;
- uint8_t hdop;
-};
-
-static __xdata struct sirf_geodetic_nav_data ao_sirf_data;
-
-struct sirf_measured_sat_data {
- uint8_t svid;
- uint8_t c_n_1;
-};
-
-struct sirf_measured_tracker_data {
- int16_t gps_week;
- uint32_t gps_tow;
- uint8_t channels;
- struct sirf_measured_sat_data sats[12];
-};
-
-static __xdata struct sirf_measured_tracker_data ao_sirf_tracker_data;
-
-static __pdata uint16_t ao_sirf_cksum;
-static __pdata uint16_t ao_sirf_len;
-
-#define ao_sirf_byte() ((uint8_t) ao_serial_getchar())
-
-static uint8_t data_byte(void)
-{
- uint8_t c = ao_sirf_byte();
- --ao_sirf_len;
- ao_sirf_cksum += c;
- return c;
-}
-
-static char __xdata *sirf_target;
-
-static void sirf_u16(uint8_t offset)
-{
- uint16_t __xdata *ptr = (uint16_t __xdata *) (sirf_target + offset);
- uint16_t val;
-
- val = data_byte() << 8;
- val |= data_byte ();
- *ptr = val;
-}
-
-static void sirf_u8(uint8_t offset)
-{
- uint8_t __xdata *ptr = (uint8_t __xdata *) (sirf_target + offset);
- uint8_t val;
-
- val = data_byte ();
- *ptr = val;
-}
-
-static void sirf_u32(uint8_t offset) __reentrant
-{
- uint32_t __xdata *ptr = (uint32_t __xdata *) (sirf_target + offset);
- uint32_t val;
-
- val = ((uint32_t) data_byte ()) << 24;
- val |= ((uint32_t) data_byte ()) << 16;
- val |= ((uint32_t) data_byte ()) << 8;
- val |= ((uint32_t) data_byte ());
- *ptr = val;
-}
-
-static void sirf_discard(uint8_t len)
-{
- while (len--)
- data_byte();
-}
-
-#define SIRF_END 0
-#define SIRF_DISCARD 1
-#define SIRF_U8 2
-#define SIRF_U16 3
-#define SIRF_U32 4
-#define SIRF_U8X10 5
-
-struct sirf_packet_parse {
- uint8_t type;
- uint8_t offset;
-};
-
-static void
-ao_sirf_parse(void __xdata *target, const struct sirf_packet_parse *parse) __reentrant
-{
- uint8_t i, offset, j;
-
- sirf_target = target;
- for (i = 0; ; i++) {
- offset = parse[i].offset;
- switch (parse[i].type) {
- case SIRF_END:
- return;
- case SIRF_DISCARD:
- sirf_discard(offset);
- break;
- case SIRF_U8:
- sirf_u8(offset);
- break;
- case SIRF_U16:
- sirf_u16(offset);
- break;
- case SIRF_U32:
- sirf_u32(offset);
- break;
- case SIRF_U8X10:
- for (j = 10; j--;)
- sirf_u8(offset++);
- break;
- }
- }
-}
-
-static const struct sirf_packet_parse geodetic_nav_data_packet[] = {
- { SIRF_DISCARD, 2 }, /* 1 nav valid */
- { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, nav_type) }, /* 3 */
- { SIRF_DISCARD, 6 }, /* 5 week number, time of week */
- { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, utc_year) }, /* 11 */
- { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_month) }, /* 13 */
- { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_day) }, /* 14 */
- { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_hour) }, /* 15 */
- { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_minute) }, /* 16 */
- { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, utc_second) }, /* 17 */
- { SIRF_DISCARD, 4 }, /* satellite id list */ /* 19 */
- { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, lat) }, /* 23 */
- { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, lon) }, /* 27 */
- { SIRF_DISCARD, 4 }, /* altitude from ellipsoid */ /* 31 */
- { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, alt_msl) }, /* 35 */
- { SIRF_DISCARD, 1 }, /* map datum */ /* 39 */
- { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, ground_speed) }, /* 40 */
- { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, course) }, /* 42 */
- { SIRF_DISCARD, 2 }, /* magnetic variation */ /* 44 */
- { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, climb_rate) }, /* 46 */
- { SIRF_DISCARD, 2 }, /* turn rate */ /* 48 */
- { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, h_error) }, /* 50 */
- { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, v_error) }, /* 54 */
- { SIRF_DISCARD, 30 }, /* time error, h_vel error, clock_bias,
- clock bias error, clock drift,
- clock drift error, distance,
- distance error, heading error */ /* 58 */
- { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, num_sv) }, /* 88 */
- { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, hdop) }, /* 89 */
- { SIRF_DISCARD, 1 }, /* additional mode info */ /* 90 */
- { SIRF_END, 0 }, /* 91 */
-};
-
-static void
-ao_sirf_parse_41(void) __reentrant
-{
- ao_sirf_parse(&ao_sirf_data, geodetic_nav_data_packet);
-}
-
-static const struct sirf_packet_parse measured_tracker_data_packet[] = {
- { SIRF_U16, offsetof (struct sirf_measured_tracker_data, gps_week) }, /* 1 week */
- { SIRF_U32, offsetof (struct sirf_measured_tracker_data, gps_tow) }, /* 3 time of week */
- { SIRF_U8, offsetof (struct sirf_measured_tracker_data, channels) }, /* 7 channels */
- { SIRF_END, 0 },
-};
-
-static const struct sirf_packet_parse measured_sat_data_packet[] = {
- { SIRF_U8, offsetof (struct sirf_measured_sat_data, svid) }, /* 0 SV id */
- { SIRF_DISCARD, 4 }, /* 1 azimuth, 2 elevation, 3 state */
- { SIRF_U8, offsetof (struct sirf_measured_sat_data, c_n_1) }, /* C/N0 1 */
- { SIRF_DISCARD, 9 }, /* C/N0 2-10 */
- { SIRF_END, 0 },
-};
-
-static void
-ao_sirf_parse_4(void) __reentrant
-{
- uint8_t i;
- ao_sirf_parse(&ao_sirf_tracker_data, measured_tracker_data_packet);
- for (i = 0; i < 12; i++)
- ao_sirf_parse(&ao_sirf_tracker_data.sats[i], measured_sat_data_packet);
-}
-
-static void
-ao_gps_setup(void) __reentrant
-{
- uint8_t i, k;
- ao_serial_set_speed(AO_SERIAL_SPEED_4800);
- for (i = 0; i < 64; i++)
- ao_serial_putchar(0x00);
- for (k = 0; k < 3; k++)
- for (i = 0; i < sizeof (ao_gps_set_nmea); i++)
- ao_serial_putchar(ao_gps_set_nmea[i]);
- ao_serial_set_speed(AO_SERIAL_SPEED_57600);
- for (i = 0; i < 64; i++)
- ao_serial_putchar(0x00);
-}
-
-static const char ao_gps_set_message_rate[] = {
- 0xa0, 0xa2, 0x00, 0x08,
- 166,
- 0,
-};
-
-void
-ao_sirf_set_message_rate(uint8_t msg, uint8_t rate) __reentrant
-{
- uint16_t cksum = 0x00a6;
- uint8_t i;
-
- for (i = 0; i < sizeof (ao_gps_set_message_rate); i++)
- ao_serial_putchar(ao_gps_set_message_rate[i]);
- ao_serial_putchar(msg);
- ao_serial_putchar(rate);
- cksum = 0xa6 + msg + rate;
- for (i = 0; i < 4; i++)
- ao_serial_putchar(0);
- ao_serial_putchar((cksum >> 8) & 0x7f);
- ao_serial_putchar(cksum & 0xff);
- ao_serial_putchar(0xb0);
- ao_serial_putchar(0xb3);
-}
-
-static const uint8_t sirf_disable[] = {
- 2,
- 9,
- 10,
- 27,
- 50,
- 52,
-};
-
-void
-ao_gps(void) __reentrant
-{
- uint8_t i, k;
- uint16_t cksum;
-
- ao_gps_setup();
- for (k = 0; k < 5; k++)
- {
- for (i = 0; i < sizeof (ao_gps_config); i++)
- ao_serial_putchar(ao_gps_config[i]);
- for (i = 0; i < sizeof (sirf_disable); i++)
- ao_sirf_set_message_rate(sirf_disable[i], 0);
- ao_sirf_set_message_rate(41, 1);
- ao_sirf_set_message_rate(4, 1);
- }
- for (;;) {
- /* Locate the begining of the next record */
- while (ao_sirf_byte() != (uint8_t) 0xa0)
- ;
- if (ao_sirf_byte() != (uint8_t) 0xa2)
- continue;
-
- /* Length */
- ao_sirf_len = ao_sirf_byte() << 8;
- ao_sirf_len |= ao_sirf_byte();
- if (ao_sirf_len > 1023)
- continue;
-
- ao_sirf_cksum = 0;
-
- /* message ID */
- i = data_byte (); /* 0 */
-
- switch (i) {
- case 41:
- if (ao_sirf_len < 90)
- break;
- ao_sirf_parse_41();
- break;
- case 4:
- if (ao_sirf_len < 187)
- break;
- ao_sirf_parse_4();
- break;
- }
- if (ao_sirf_len != 0)
- continue;
-
- /* verify checksum and end sequence */
- ao_sirf_cksum &= 0x7fff;
- cksum = ao_sirf_byte() << 8;
- cksum |= ao_sirf_byte();
- if (ao_sirf_cksum != cksum)
- continue;
- if (ao_sirf_byte() != (uint8_t) 0xb0)
- continue;
- if (ao_sirf_byte() != (uint8_t) 0xb3)
- continue;
-
- switch (i) {
- case 41:
- ao_mutex_get(&ao_gps_mutex);
- ao_gps_tick = ao_time();
- ao_gps_data.hour = ao_sirf_data.utc_hour;
- ao_gps_data.minute = ao_sirf_data.utc_minute;
- ao_gps_data.second = ao_sirf_data.utc_second / 1000;
- ao_gps_data.flags = ((ao_sirf_data.num_sv << AO_GPS_NUM_SAT_SHIFT) & AO_GPS_NUM_SAT_MASK) | AO_GPS_RUNNING;
- if ((ao_sirf_data.nav_type & NAV_TYPE_GPS_FIX_TYPE_MASK) >= NAV_TYPE_4_SV_KF)
- ao_gps_data.flags |= AO_GPS_VALID;
- ao_gps_data.latitude = ao_sirf_data.lat;
- ao_gps_data.longitude = ao_sirf_data.lon;
- ao_gps_data.altitude = ao_sirf_data.alt_msl / 100;
- ao_gps_data.ground_speed = ao_sirf_data.ground_speed;
- ao_gps_data.course = ao_sirf_data.course / 200;
- ao_gps_data.hdop = ao_sirf_data.hdop;
- ao_gps_data.climb_rate = ao_sirf_data.climb_rate;
- ao_gps_data.flags |= AO_GPS_COURSE_VALID;
-#if 0
- if (ao_sirf_data.h_error > 6553500)
- ao_gps_data.h_error = 65535;
- else
- ao_gps_data.h_error = ao_sirf_data.h_error / 100;
- if (ao_sirf_data.v_error > 6553500)
- ao_gps_data.v_error = 65535;
- else
- ao_gps_data.v_error = ao_sirf_data.v_error / 100;
-#endif
- ao_mutex_put(&ao_gps_mutex);
- ao_wakeup(&ao_gps_data);
- break;
- case 4:
- ao_mutex_get(&ao_gps_mutex);
- ao_gps_tracking_data.channels = ao_sirf_tracker_data.channels;
- for (i = 0; i < 12; i++) {
- ao_gps_tracking_data.sats[i].svid = ao_sirf_tracker_data.sats[i].svid;
- ao_gps_tracking_data.sats[i].c_n_1 = ao_sirf_tracker_data.sats[i].c_n_1;
- }
- ao_mutex_put(&ao_gps_mutex);
- ao_wakeup(&ao_gps_tracking_data);
- break;
- }
- }
-}
-
-__xdata struct ao_task ao_gps_task;
-
-void
-ao_gps_init(void)
-{
- ao_add_task(&ao_gps_task, ao_gps, "gps");
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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_GPS_TEST
-#include "ao.h"
-#endif
-
-#define AO_GPS_LEADER 2
-
-static __code char ao_gps_header[] = "GP";
-
-__xdata uint8_t ao_gps_mutex;
-static __data char ao_gps_char;
-static __pdata uint8_t ao_gps_cksum;
-static __pdata uint8_t ao_gps_error;
-
-__pdata uint16_t ao_gps_tick;
-__xdata struct ao_telemetry_location ao_gps_data;
-__xdata struct ao_telemetry_satellite ao_gps_tracking_data;
-
-static __pdata uint16_t ao_gps_next_tick;
-static __xdata struct ao_telemetry_location ao_gps_next;
-static __pdata uint8_t ao_gps_date_flags;
-static __xdata struct ao_telemetry_satellite ao_gps_tracking_next;
-
-#define STQ_S 0xa0, 0xa1
-#define STQ_E 0x0d, 0x0a
-#define SKYTRAQ_MSG_2(id,a,b) \
- STQ_S, 0, 3, id, a,b, (id^a^b), STQ_E
-#define SKYTRAQ_MSG_3(id,a,b,c) \
- STQ_S, 0, 4, id, a,b,c, (id^a^b^c), STQ_E
-#define SKYTRAQ_MSG_8(id,a,b,c,d,e,f,g,h) \
- STQ_S, 0, 9, id, a,b,c,d,e,f,g,h, (id^a^b^c^d^e^f^g^h), STQ_E
-#define SKYTRAQ_MSG_14(id,a,b,c,d,e,f,g,h,i,j,k,l,m,n) \
- STQ_S, 0,15, id, a,b,c,d,e,f,g,h,i,j,k,l,m,n, \
- (id^a^b^c^d^e^f^g^h^i^j^k^l^m^n), STQ_E
-
-static __code uint8_t ao_gps_config[] = {
- SKYTRAQ_MSG_8(0x08, 1, 1, 1, 1, 1, 1, 1, 0), /* configure nmea */
- /* gga interval */
- /* gsa interval */
- /* gsv interval */
- /* gll interval */
- /* rmc interval */
- /* vtg interval */
- /* zda interval */
- /* attributes (0 = update to sram, 1 = update flash too) */
-
- SKYTRAQ_MSG_2(0x3c, 0x00, 0x00), /* configure navigation mode */
- /* 0 = car, 1 = pedestrian */
- /* 0 = update to sram, 1 = update sram + flash */
-};
-
-static void
-ao_gps_lexchar(void)
-{
- if (ao_gps_error)
- ao_gps_char = '\n';
- else
- ao_gps_char = ao_serial_getchar();
- ao_gps_cksum ^= ao_gps_char;
-}
-
-void
-ao_gps_skip_field(void)
-{
- while (ao_gps_char != ',' && ao_gps_char != '*' && ao_gps_char != '\n')
- ao_gps_lexchar();
-}
-
-void
-ao_gps_skip_sep(void)
-{
- if (ao_gps_char == ',' || ao_gps_char == '.' || ao_gps_char == '*')
- ao_gps_lexchar();
-}
-
-__pdata static uint8_t ao_gps_num_width;
-
-static int16_t
-ao_gps_decimal(uint8_t max_width)
-{
- int16_t v;
- __pdata uint8_t neg = 0;
-
- ao_gps_skip_sep();
- if (ao_gps_char == '-') {
- neg = 1;
- ao_gps_lexchar();
- }
- v = 0;
- ao_gps_num_width = 0;
- while (ao_gps_num_width < max_width) {
- if (ao_gps_char < '0' || '9' < ao_gps_char)
- break;
- v = v * (int16_t) 10 + ao_gps_char - '0';
- ao_gps_num_width++;
- ao_gps_lexchar();
- }
- if (neg)
- v = -v;
- return v;
-}
-
-static uint8_t
-ao_gps_hex(uint8_t max_width)
-{
- uint8_t v, d;
-
- ao_gps_skip_sep();
- v = 0;
- ao_gps_num_width = 0;
- while (ao_gps_num_width < max_width) {
- if ('0' <= ao_gps_char && ao_gps_char <= '9')
- d = ao_gps_char - '0';
- else if ('A' <= ao_gps_char && ao_gps_char <= 'F')
- d = ao_gps_char - 'A' + 10;
- else if ('a' <= ao_gps_char && ao_gps_char <= 'f')
- d = ao_gps_char - 'a' + 10;
- else
- break;
- v = (v << 4) | d;
- ao_gps_num_width++;
- ao_gps_lexchar();
- }
- return v;
-}
-
-static int32_t
-ao_gps_parse_pos(uint8_t deg_width) __reentrant
-{
- int32_t d;
- int32_t m;
- int32_t f;
-
- d = ao_gps_decimal(deg_width);
- m = ao_gps_decimal(2);
- if (ao_gps_char == '.') {
- f = ao_gps_decimal(4);
- while (ao_gps_num_width < 4) {
- f *= 10;
- ao_gps_num_width++;
- }
- } else {
- f = 0;
- if (ao_gps_char != ',')
- ao_gps_error = 1;
- }
- d = d * 10000000l;
- m = m * 10000l + f;
- d = d + m * 50 / 3;
- return d;
-}
-
-static uint8_t
-ao_gps_parse_flag(char no_c, char yes_c) __reentrant
-{
- uint8_t ret = 0;
- ao_gps_skip_sep();
- if (ao_gps_char == yes_c)
- ret = 1;
- else if (ao_gps_char == no_c)
- ret = 0;
- else
- ao_gps_error = 1;
- ao_gps_lexchar();
- return ret;
-}
-
-static void
-ao_nmea_gga()
-{
- uint8_t i;
-
- /* Now read the data into the gps data record
- *
- * $GPGGA,025149.000,4528.1723,N,12244.2480,W,1,05,2.0,103.5,M,-19.5,M,,0000*66
- *
- * Essential fix data
- *
- * 025149.000 time (02:51:49.000 GMT)
- * 4528.1723,N Latitude 45°28.1723' N
- * 12244.2480,W Longitude 122°44.2480' W
- * 1 Fix quality:
- * 0 = invalid
- * 1 = GPS fix (SPS)
- * 2 = DGPS fix
- * 3 = PPS fix
- * 4 = Real Time Kinematic
- * 5 = Float RTK
- * 6 = estimated (dead reckoning)
- * 7 = Manual input mode
- * 8 = Simulation mode
- * 05 Number of satellites (5)
- * 2.0 Horizontal dilution
- * 103.5,M Altitude, 103.5M above msl
- * -19.5,M Height of geoid above WGS84 ellipsoid
- * ? time in seconds since last DGPS update
- * 0000 DGPS station ID
- * *66 checksum
- */
-
- ao_gps_next_tick = ao_time();
- ao_gps_next.flags = AO_GPS_RUNNING | ao_gps_date_flags;
- ao_gps_next.hour = ao_gps_decimal(2);
- ao_gps_next.minute = ao_gps_decimal(2);
- ao_gps_next.second = ao_gps_decimal(2);
- ao_gps_skip_field(); /* skip seconds fraction */
-
- ao_gps_next.latitude = ao_gps_parse_pos(2);
- if (ao_gps_parse_flag('N', 'S'))
- ao_gps_next.latitude = -ao_gps_next.latitude;
- ao_gps_next.longitude = ao_gps_parse_pos(3);
- if (ao_gps_parse_flag('E', 'W'))
- ao_gps_next.longitude = -ao_gps_next.longitude;
-
- i = ao_gps_decimal(0xff);
- if (i == 1)
- ao_gps_next.flags |= AO_GPS_VALID;
-
- i = ao_gps_decimal(0xff) << AO_GPS_NUM_SAT_SHIFT;
- if (i > AO_GPS_NUM_SAT_MASK)
- i = AO_GPS_NUM_SAT_MASK;
- ao_gps_next.flags |= i;
-
- ao_gps_lexchar();
- i = ao_gps_decimal(0xff);
- if (i <= 50) {
- i = (uint8_t) 5 * i;
- if (ao_gps_char == '.')
- i = (i + ((uint8_t) ao_gps_decimal(1) >> 1));
- } else
- i = 255;
- ao_gps_next.hdop = i;
- ao_gps_skip_field();
-
- ao_gps_next.altitude = ao_gps_decimal(0xff);
- ao_gps_skip_field(); /* skip any fractional portion */
-
- /* Skip remaining fields */
- while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') {
- ao_gps_lexchar();
- ao_gps_skip_field();
- }
- if (ao_gps_char == '*') {
- uint8_t cksum = ao_gps_cksum ^ '*';
- if (cksum != ao_gps_hex(2))
- ao_gps_error = 1;
- } else
- ao_gps_error = 1;
- if (!ao_gps_error) {
- ao_mutex_get(&ao_gps_mutex);
- ao_gps_tick = ao_gps_next_tick;
- memcpy(&ao_gps_data, &ao_gps_next, sizeof (ao_gps_data));
- ao_mutex_put(&ao_gps_mutex);
- ao_wakeup(&ao_gps_data);
- }
-}
-
-static void
-ao_nmea_gsv(void)
-{
- char c;
- uint8_t i;
- uint8_t done;
- /* Now read the data into the GPS tracking data record
- *
- * $GPGSV,3,1,12,05,54,069,45,12,44,061,44,21,07,184,46,22,78,289,47*72<CR><LF>
- *
- * Satellites in view data
- *
- * 3 Total number of GSV messages
- * 1 Sequence number of current GSV message
- * 12 Total sats in view (0-12)
- * 05 SVID
- * 54 Elevation
- * 069 Azimuth
- * 45 C/N0 in dB
- * ... other SVIDs
- * 72 checksum
- */
- c = ao_gps_decimal(1); /* total messages */
- i = ao_gps_decimal(1); /* message sequence */
- if (i == 1) {
- ao_gps_tracking_next.channels = 0;
- }
- done = (uint8_t) c == i;
- ao_gps_lexchar();
- ao_gps_skip_field(); /* sats in view */
- while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') {
- i = ao_gps_tracking_next.channels;
- c = ao_gps_decimal(2); /* SVID */
- if (i < AO_MAX_GPS_TRACKING)
- ao_gps_tracking_next.sats[i].svid = c;
- ao_gps_lexchar();
- ao_gps_skip_field(); /* elevation */
- ao_gps_lexchar();
- ao_gps_skip_field(); /* azimuth */
- c = ao_gps_decimal(2); /* C/N0 */
- if (i < AO_MAX_GPS_TRACKING) {
- if ((ao_gps_tracking_next.sats[i].c_n_1 = c) != 0)
- ao_gps_tracking_next.channels = i + 1;
- }
- }
- if (ao_gps_char == '*') {
- uint8_t cksum = ao_gps_cksum ^ '*';
- if (cksum != ao_gps_hex(2))
- ao_gps_error = 1;
- }
- else
- ao_gps_error = 1;
- if (ao_gps_error)
- ao_gps_tracking_next.channels = 0;
- else if (done) {
- ao_mutex_get(&ao_gps_mutex);
- memcpy(&ao_gps_tracking_data, &ao_gps_tracking_next,
- sizeof(ao_gps_tracking_data));
- ao_mutex_put(&ao_gps_mutex);
- ao_wakeup(&ao_gps_tracking_data);
- }
-}
-
-static void
-ao_nmea_rmc(void)
-{
- char a, c;
- uint8_t i;
- /* Parse the RMC record to read out the current date */
-
- /* $GPRMC,111636.932,A,2447.0949,N,12100.5223,E,000.0,000.0,030407,,,A*61
- *
- * Recommended Minimum Specific GNSS Data
- *
- * 111636.932 UTC time 11:16:36.932
- * A Data Valid (V = receiver warning)
- * 2447.0949 Latitude
- * N North/south indicator
- * 12100.5223 Longitude
- * E East/west indicator
- * 000.0 Speed over ground
- * 000.0 Course over ground
- * 030407 UTC date (ddmmyy format)
- * A Mode indicator:
- * N = data not valid
- * A = autonomous mode
- * D = differential mode
- * E = estimated (dead reckoning) mode
- * M = manual input mode
- * S = simulator mode
- * 61 checksum
- */
- ao_gps_skip_field();
- for (i = 0; i < 8; i++) {
- ao_gps_lexchar();
- ao_gps_skip_field();
- }
- a = ao_gps_decimal(2);
- c = ao_gps_decimal(2);
- i = ao_gps_decimal(2);
- /* Skip remaining fields */
- while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') {
- ao_gps_lexchar();
- ao_gps_skip_field();
- }
- if (ao_gps_char == '*') {
- uint8_t cksum = ao_gps_cksum ^ '*';
- if (cksum != ao_gps_hex(2))
- ao_gps_error = 1;
- } else
- ao_gps_error = 1;
- if (!ao_gps_error) {
- ao_gps_next.year = i;
- ao_gps_next.month = c;
- ao_gps_next.day = a;
- ao_gps_date_flags = AO_GPS_DATE_VALID;
- }
-}
-
-#define ao_skytraq_sendstruct(s) ao_skytraq_sendbytes((s), sizeof(s))
-
-static void
-ao_skytraq_sendbytes(__code uint8_t *b, uint8_t l)
-{
- while (l--) {
- uint8_t c = *b++;
- if (c == 0xa0)
- ao_delay(AO_MS_TO_TICKS(500));
- ao_serial_putchar(c);
- }
-}
-
-static void
-ao_gps_nmea_parse(void)
-{
- uint8_t a, b, c;
-
- ao_gps_cksum = 0;
- ao_gps_error = 0;
-
- for (a = 0; a < AO_GPS_LEADER; a++) {
- ao_gps_lexchar();
- if (ao_gps_char != ao_gps_header[a])
- return;
- }
-
- ao_gps_lexchar();
- a = ao_gps_char;
- ao_gps_lexchar();
- b = ao_gps_char;
- ao_gps_lexchar();
- c = ao_gps_char;
- ao_gps_lexchar();
-
- if (ao_gps_char != ',')
- return;
-
- if (a == (uint8_t) 'G' && b == (uint8_t) 'G' && c == (uint8_t) 'A') {
- ao_nmea_gga();
- } else if (a == (uint8_t) 'G' && b == (uint8_t) 'S' && c == (uint8_t) 'V') {
- ao_nmea_gsv();
- } else if (a == (uint8_t) 'R' && b == (uint8_t) 'M' && c == (uint8_t) 'C') {
- ao_nmea_rmc();
- }
-}
-
-void
-ao_gps(void) __reentrant
-{
- ao_serial_set_speed(AO_SERIAL_SPEED_9600);
-
- /* give skytraq time to boot in case of cold start */
- ao_delay(AO_MS_TO_TICKS(2000));
-
- ao_skytraq_sendstruct(ao_gps_config);
-
- for (;;) {
- /* Locate the begining of the next record */
- if (ao_serial_getchar() == '$') {
- ao_gps_nmea_parse();
- }
-
- }
-}
-
-__xdata struct ao_task ao_gps_task;
-
-static void
-gps_dump(void) __reentrant
-{
- uint8_t i;
- ao_mutex_get(&ao_gps_mutex);
- printf ("Date: %02d/%02d/%02d\n", ao_gps_data.year, ao_gps_data.month, ao_gps_data.day);
- printf ("Time: %02d:%02d:%02d\n", ao_gps_data.hour, ao_gps_data.minute, ao_gps_data.second);
- printf ("Lat/Lon: %ld %ld\n", ao_gps_data.latitude, ao_gps_data.longitude);
- printf ("Alt: %d\n", ao_gps_data.altitude);
- printf ("Flags: 0x%x\n", ao_gps_data.flags);
- printf ("Sats: %d", ao_gps_tracking_data.channels);
- for (i = 0; i < ao_gps_tracking_data.channels; i++)
- printf (" %d %d",
- ao_gps_tracking_data.sats[i].svid,
- ao_gps_tracking_data.sats[i].c_n_1);
- printf ("\ndone\n");
- ao_mutex_put(&ao_gps_mutex);
-}
-
-__code struct ao_cmds ao_gps_cmds[] = {
- { gps_dump, "g\0Display GPS" },
- { 0, NULL },
-};
-
-void
-ao_gps_init(void)
-{
- ao_add_task(&ao_gps_task, ao_gps, "gps");
- ao_cmd_register(&ao_gps_cmds[0]);
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#define AO_GPS_TEST
-#include "ao_host.h"
-#include <termios.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#define AO_GPS_NUM_SAT_MASK (0xf << 0)
-#define AO_GPS_NUM_SAT_SHIFT (0)
-
-#define AO_GPS_VALID (1 << 4)
-#define AO_GPS_RUNNING (1 << 5)
-#define AO_GPS_DATE_VALID (1 << 6)
-#define AO_GPS_COURSE_VALID (1 << 7)
-
-struct ao_gps_orig {
- uint8_t year;
- uint8_t month;
- uint8_t day;
- uint8_t hour;
- uint8_t minute;
- uint8_t second;
- uint8_t flags;
- int32_t latitude; /* degrees * 10⁷ */
- int32_t longitude; /* degrees * 10⁷ */
- int16_t altitude; /* m */
- uint16_t ground_speed; /* cm/s */
- uint8_t course; /* degrees / 2 */
- uint8_t hdop; /* * 5 */
- int16_t climb_rate; /* cm/s */
- uint16_t h_error; /* m */
- uint16_t v_error; /* m */
-};
-
-#define SIRF_SAT_STATE_ACQUIRED (1 << 0)
-#define SIRF_SAT_STATE_CARRIER_PHASE_VALID (1 << 1)
-#define SIRF_SAT_BIT_SYNC_COMPLETE (1 << 2)
-#define SIRF_SAT_SUBFRAME_SYNC_COMPLETE (1 << 3)
-#define SIRF_SAT_CARRIER_PULLIN_COMPLETE (1 << 4)
-#define SIRF_SAT_CODE_LOCKED (1 << 5)
-#define SIRF_SAT_ACQUISITION_FAILED (1 << 6)
-#define SIRF_SAT_EPHEMERIS_AVAILABLE (1 << 7)
-
-struct ao_gps_sat_orig {
- uint8_t svid;
- uint8_t c_n_1;
-};
-
-#define AO_MAX_GPS_TRACKING 12
-
-struct ao_gps_tracking_orig {
- uint8_t channels;
- struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING];
-};
-
-#define ao_telemetry_location ao_gps_orig
-#define ao_telemetry_satellite ao_gps_tracking_orig
-#define ao_telemetry_satellite_info ao_gps_sat_orig
-
-void
-ao_mutex_get(uint8_t *mutex)
-{
-}
-
-void
-ao_mutex_put(uint8_t *mutex)
-{
-}
-
-static int
-ao_gps_fd;
-
-static void
-ao_dbg_char(char c)
-{
- char line[128];
- line[0] = '\0';
- if (c < ' ') {
- if (c == '\n')
- sprintf (line, "\n");
- else
- sprintf (line, "\\%02x", ((int) c) & 0xff);
- } else {
- sprintf (line, "%c", c);
- }
- write(1, line, strlen(line));
-}
-
-#define QUEUE_LEN 4096
-
-static char input_queue[QUEUE_LEN];
-int input_head, input_tail;
-
-#include <sys/time.h>
-
-int
-get_millis(void)
-{
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return tv.tv_sec * 1000 + tv.tv_usec / 1000;
-}
-
-static void
-check_sirf_message(char *from, uint8_t *msg, int len)
-{
- uint16_t encoded_len, encoded_cksum;
- uint16_t cksum;
- uint8_t id;
- int i;
-
- if (msg[0] != 0xa0 || msg[1] != 0xa2) {
- printf ("bad header\n");
- return;
- }
- if (len < 7) {
- printf("short\n");
- return;
- }
- if (msg[len-1] != 0xb3 || msg[len-2] != 0xb0) {
- printf ("bad trailer\n");
- return;
- }
- encoded_len = (msg[2] << 8) | msg[3];
- id = msg[4];
-/* printf ("%9d: %3d\n", get_millis(), id); */
- if (encoded_len != len - 8) {
- if (id != 52)
- printf ("length mismatch (got %d, wanted %d)\n",
- len - 8, encoded_len);
- return;
- }
- encoded_cksum = (msg[len - 4] << 8) | msg[len-3];
- cksum = 0;
- for (i = 4; i < len - 4; i++)
- cksum = (cksum + msg[i]) & 0x7fff;
- if (encoded_cksum != cksum) {
- printf ("cksum mismatch (got %04x wanted %04x)\n",
- cksum, encoded_cksum);
- return;
- }
- id = msg[4];
- switch (id) {
- case 41:{
- int off = 4;
-
- uint8_t id;
- uint16_t nav_valid;
- uint16_t nav_type;
- uint16_t week;
- uint32_t tow;
- uint16_t year;
- uint8_t month;
- uint8_t day;
- uint8_t hour;
- uint8_t minute;
- uint16_t second;
- uint32_t sat_list;
- int32_t lat;
- int32_t lon;
- int32_t alt_ell;
- int32_t alt_msl;
- int8_t datum;
- uint16_t sog;
- uint16_t cog;
- int16_t mag_var;
- int16_t climb_rate;
- int16_t heading_rate;
- uint32_t h_error;
- uint32_t v_error;
- uint32_t t_error;
- uint16_t h_v_error;
-
-#define get_u8(u) u = (msg[off]); off+= 1
-#define get_u16(u) u = (msg[off] << 8) | (msg[off + 1]); off+= 2
-#define get_u32(u) u = (msg[off] << 24) | (msg[off + 1] << 16) | (msg[off+2] << 8) | (msg[off+3]); off+= 4
-
- get_u8(id);
- get_u16(nav_valid);
- get_u16(nav_type);
- get_u16(week);
- get_u32(tow);
- get_u16(year);
- get_u8(month);
- get_u8(day);
- get_u8(hour);
- get_u8(minute);
- get_u16(second);
- get_u32(sat_list);
- get_u32(lat);
- get_u32(lon);
- get_u32(alt_ell);
- get_u32(alt_msl);
- get_u8(datum);
- get_u16(sog);
- get_u16(cog);
- get_u16(mag_var);
- get_u16(climb_rate);
- get_u16(heading_rate);
- get_u32(h_error);
- get_u32(v_error);
- get_u32(t_error);
- get_u16(h_v_error);
-
-
- printf ("Geodetic Navigation Data (41):\n");
- printf ("\tNav valid %04x\n", nav_valid);
- printf ("\tNav type %04x\n", nav_type);
- printf ("\tWeek %5d", week);
- printf (" TOW %9d", tow);
- printf (" %4d-%2d-%2d %02d:%02d:%07.4f\n",
- year, month, day,
- hour, minute, second / 1000.0);
- printf ("\tsats: %08x\n", sat_list);
- printf ("\tlat: %g", lat / 1.0e7);
- printf (" lon: %g", lon / 1.0e7);
- printf (" alt_ell: %g", alt_ell / 100.0);
- printf (" alt_msll: %g", alt_msl / 100.0);
- printf (" datum: %d\n", datum);
- printf ("\tground speed: %g", sog / 100.0);
- printf (" course: %g", cog / 100.0);
- printf (" climb: %g", climb_rate / 100.0);
- printf (" heading rate: %g\n", heading_rate / 100.0);
- printf ("\th error: %g", h_error / 100.0);
- printf (" v error: %g", v_error / 100.0);
- printf (" t error: %g", t_error / 100.0);
- printf (" h vel error: %g\n", h_v_error / 100.0);
- break;
- }
- case 4: {
- int off = 4;
- uint8_t id;
- int16_t gps_week;
- uint32_t gps_tow;
- uint8_t channels;
- int j, k;
-
- get_u8(id);
- get_u16(gps_week);
- get_u32(gps_tow);
- get_u8(channels);
-
- printf ("Measured Tracker Data (4):\n");
- printf ("GPS week: %d\n", gps_week);
- printf ("GPS time of week: %d\n", gps_tow);
- printf ("channels: %d\n", channels);
- for (j = 0; j < 12; j++) {
- uint8_t svid, azimuth, elevation;
- uint16_t state;
- uint8_t c_n[10];
- get_u8(svid);
- get_u8(azimuth);
- get_u8(elevation);
- get_u16(state);
- for (k = 0; k < 10; k++) {
- get_u8(c_n[k]);
- }
- printf ("Sat %3d:", svid);
- printf (" aziumuth: %6.1f", azimuth * 1.5);
- printf (" elevation: %6.1f", elevation * 0.5);
- printf (" state: 0x%02x", state);
- printf (" c_n:");
- for (k = 0; k < 10; k++)
- printf(" %3d", c_n[k]);
- if (state & SIRF_SAT_STATE_ACQUIRED)
- printf(" acq,");
- if (state & SIRF_SAT_STATE_CARRIER_PHASE_VALID)
- printf(" car,");
- if (state & SIRF_SAT_BIT_SYNC_COMPLETE)
- printf(" bit,");
- if (state & SIRF_SAT_SUBFRAME_SYNC_COMPLETE)
- printf(" sub,");
- if (state & SIRF_SAT_CARRIER_PULLIN_COMPLETE)
- printf(" pullin,");
- if (state & SIRF_SAT_CODE_LOCKED)
- printf(" code,");
- if (state & SIRF_SAT_ACQUISITION_FAILED)
- printf(" fail,");
- if (state & SIRF_SAT_EPHEMERIS_AVAILABLE)
- printf(" ephem,");
- printf ("\n");
- }
- break;
- }
- default:
- return;
- printf ("%s %4d:", from, encoded_len);
- for (i = 4; i < len - 4; i++) {
- if (((i - 4) & 0xf) == 0)
- printf("\n ");
- printf (" %3d", msg[i]);
- }
- printf ("\n");
- }
-}
-
-static uint8_t sirf_message[4096];
-static int sirf_message_len;
-static uint8_t sirf_in_message[4096];
-static int sirf_in_len;
-
-char
-ao_serial_getchar(void)
-{
- char c;
- uint8_t uc;
-
- while (input_head == input_tail) {
- for (;;) {
- input_tail = read(ao_gps_fd, input_queue, QUEUE_LEN);
- if (input_tail < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
- perror ("getchar");
- exit (1);
- }
- input_head = 0;
- break;
- }
- }
- c = input_queue[input_head];
- input_head = (input_head + 1) % QUEUE_LEN;
- uc = c;
- if (sirf_in_len || uc == 0xa0) {
- if (sirf_in_len < 4096)
- sirf_in_message[sirf_in_len++] = uc;
- if (uc == 0xb3) {
- check_sirf_message("recv", sirf_in_message, sirf_in_len);
- sirf_in_len = 0;
- }
- }
- return c;
-}
-
-
-void
-ao_serial_putchar(char c)
-{
- int i;
- uint8_t uc = (uint8_t) c;
-
- if (sirf_message_len || uc == 0xa0) {
- if (sirf_message_len < 4096)
- sirf_message[sirf_message_len++] = uc;
- if (uc == 0xb3) {
- check_sirf_message("send", sirf_message, sirf_message_len);
- sirf_message_len = 0;
- }
- }
- for (;;) {
- i = write(ao_gps_fd, &c, 1);
- if (i == 1) {
- if ((uint8_t) c == 0xb3 || c == '\r') {
- static const struct timespec delay = {
- .tv_sec = 0,
- .tv_nsec = 100 * 1000 * 1000
- };
- tcdrain(ao_gps_fd);
-// nanosleep(&delay, NULL);
- }
- break;
- }
- if (i < 0 && (errno == EINTR || errno == EAGAIN))
- continue;
- perror("putchar");
- exit(1);
- }
-}
-
-#define AO_SERIAL_SPEED_4800 0
-#define AO_SERIAL_SPEED_57600 1
-
-static void
-ao_serial_set_speed(uint8_t speed)
-{
- int fd = ao_gps_fd;
- struct termios termios;
-
- tcdrain(fd);
- tcgetattr(fd, &termios);
- switch (speed) {
- case AO_SERIAL_SPEED_4800:
- cfsetspeed(&termios, B4800);
- break;
- case AO_SERIAL_SPEED_57600:
- cfsetspeed(&termios, B57600);
- break;
- }
- tcsetattr(fd, TCSAFLUSH, &termios);
- tcflush(fd, TCIFLUSH);
-}
-
-#define ao_time() 0
-
-#include "ao_gps_print.c"
-#include "ao_gps_sirf.c"
-
-void
-ao_dump_state(void *wchan)
-{
- double lat, lon;
- int i;
- if (wchan == &ao_gps_data)
- ao_gps_print(&ao_gps_data);
- else
- ao_gps_tracking_print(&ao_gps_tracking_data);
- putchar('\n');
- return;
- printf ("%02d:%02d:%02d",
- ao_gps_data.hour, ao_gps_data.minute,
- ao_gps_data.second);
- printf (" nsat %d %svalid",
- ao_gps_data.flags & AO_GPS_NUM_SAT_MASK,
- ao_gps_data.flags & AO_GPS_VALID ? "" : "not ");
- printf (" lat %g lon %g alt %d",
- ao_gps_data.latitude / 1.0e7,
- ao_gps_data.longitude / 1.0e7,
- ao_gps_data.altitude);
- printf (" speed %g climb %g course %d",
- ao_gps_data.ground_speed / 100.0,
- ao_gps_data.climb_rate / 100.0,
- ao_gps_data.course * 2);
- printf (" hdop %g h_error %d v_error %d",
- ao_gps_data.hdop / 5.0,
- ao_gps_data.h_error, ao_gps_data.v_error);
- printf("\n");
- printf ("\t");
- for (i = 0; i < 12; i++)
- printf (" %2d(%02d)",
- ao_gps_tracking_data.sats[i].svid,
- ao_gps_tracking_data.sats[i].c_n_1);
- printf ("\n");
-}
-
-int
-ao_gps_open(const char *tty)
-{
- struct termios termios;
- int fd;
-
- fd = open (tty, O_RDWR);
- if (fd < 0)
- return -1;
-
- tcgetattr(fd, &termios);
- cfmakeraw(&termios);
- cfsetspeed(&termios, B4800);
- tcsetattr(fd, TCSAFLUSH, &termios);
-
- tcdrain(fd);
- tcflush(fd, TCIFLUSH);
- return fd;
-}
-
-#include <getopt.h>
-
-static const struct option options[] = {
- { .name = "tty", .has_arg = 1, .val = 'T' },
- { 0, 0, 0, 0},
-};
-
-static void usage(char *program)
-{
- fprintf(stderr, "usage: %s [--tty <tty-name>]\n", program);
- exit(1);
-}
-
-int
-main (int argc, char **argv)
-{
- char *tty = "/dev/ttyUSB0";
- int c;
-
- while ((c = getopt_long(argc, argv, "T:", options, NULL)) != -1) {
- switch (c) {
- case 'T':
- tty = optarg;
- break;
- default:
- usage(argv[0]);
- break;
- }
- }
- ao_gps_fd = ao_gps_open(tty);
- if (ao_gps_fd < 0) {
- perror (tty);
- exit (1);
- }
- ao_gps_setup();
- ao_gps();
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#define AO_GPS_TEST
-#include "ao_host.h"
-#include <termios.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#define AO_GPS_NUM_SAT_MASK (0xf << 0)
-#define AO_GPS_NUM_SAT_SHIFT (0)
-
-#define AO_GPS_VALID (1 << 4)
-#define AO_GPS_RUNNING (1 << 5)
-#define AO_GPS_DATE_VALID (1 << 6)
-#define AO_GPS_COURSE_VALID (1 << 7)
-
-struct ao_gps_orig {
- uint8_t year;
- uint8_t month;
- uint8_t day;
- uint8_t hour;
- uint8_t minute;
- uint8_t second;
- uint8_t flags;
- int32_t latitude; /* degrees * 10⁷ */
- int32_t longitude; /* degrees * 10⁷ */
- int16_t altitude; /* m */
- uint16_t ground_speed; /* cm/s */
- uint8_t course; /* degrees / 2 */
- uint8_t hdop; /* * 5 */
- int16_t climb_rate; /* cm/s */
- uint16_t h_error; /* m */
- uint16_t v_error; /* m */
-};
-
-#define SIRF_SAT_STATE_ACQUIRED (1 << 0)
-#define SIRF_SAT_STATE_CARRIER_PHASE_VALID (1 << 1)
-#define SIRF_SAT_BIT_SYNC_COMPLETE (1 << 2)
-#define SIRF_SAT_SUBFRAME_SYNC_COMPLETE (1 << 3)
-#define SIRF_SAT_CARRIER_PULLIN_COMPLETE (1 << 4)
-#define SIRF_SAT_CODE_LOCKED (1 << 5)
-#define SIRF_SAT_ACQUISITION_FAILED (1 << 6)
-#define SIRF_SAT_EPHEMERIS_AVAILABLE (1 << 7)
-
-struct ao_gps_sat_orig {
- uint8_t svid;
- uint8_t c_n_1;
-};
-
-#define AO_MAX_GPS_TRACKING 12
-
-struct ao_gps_tracking_orig {
- uint8_t channels;
- struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING];
-};
-
-#define ao_telemetry_location ao_gps_orig
-#define ao_telemetry_satellite ao_gps_tracking_orig
-#define ao_telemetry_satellite_info ao_gps_sat_orig
-
-void
-ao_mutex_get(uint8_t *mutex)
-{
-}
-
-void
-ao_mutex_put(uint8_t *mutex)
-{
-}
-
-static int
-ao_gps_fd;
-
-static void
-ao_dbg_char(char c)
-{
- char line[128];
- line[0] = '\0';
- if (c < ' ') {
- if (c == '\n')
- sprintf (line, "\n");
- else
- sprintf (line, "\\%02x", ((int) c) & 0xff);
- } else {
- sprintf (line, "%c", c);
- }
- write(1, line, strlen(line));
-}
-
-#define QUEUE_LEN 4096
-
-static char input_queue[QUEUE_LEN];
-int input_head, input_tail;
-
-#include <sys/time.h>
-
-int
-get_millis(void)
-{
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return tv.tv_sec * 1000 + tv.tv_usec / 1000;
-}
-
-static void
-check_skytraq_message(char *from, uint8_t *msg, int len)
-{
- uint16_t encoded_len, encoded_cksum;
- uint16_t cksum;
- uint8_t id;
- int i;
-
-// fwrite(msg, 1, len, stdout);
- return;
- if (msg[0] != 0xa0 || msg[1] != 0xa2) {
- printf ("bad header\n");
- return;
- }
- if (len < 7) {
- printf("short\n");
- return;
- }
- if (msg[len-1] != 0xb3 || msg[len-2] != 0xb0) {
- printf ("bad trailer\n");
- return;
- }
- encoded_len = (msg[2] << 8) | msg[3];
- id = msg[4];
-/* printf ("%9d: %3d\n", get_millis(), id); */
- if (encoded_len != len - 8) {
- if (id != 52)
- printf ("length mismatch (got %d, wanted %d)\n",
- len - 8, encoded_len);
- return;
- }
- encoded_cksum = (msg[len - 4] << 8) | msg[len-3];
- cksum = 0;
- for (i = 4; i < len - 4; i++)
- cksum = (cksum + msg[i]) & 0x7fff;
- if (encoded_cksum != cksum) {
- printf ("cksum mismatch (got %04x wanted %04x)\n",
- cksum, encoded_cksum);
- return;
- }
- id = msg[4];
- switch (id) {
- case 41:{
- int off = 4;
-
- uint8_t id;
- uint16_t nav_valid;
- uint16_t nav_type;
- uint16_t week;
- uint32_t tow;
- uint16_t year;
- uint8_t month;
- uint8_t day;
- uint8_t hour;
- uint8_t minute;
- uint16_t second;
- uint32_t sat_list;
- int32_t lat;
- int32_t lon;
- int32_t alt_ell;
- int32_t alt_msl;
- int8_t datum;
- uint16_t sog;
- uint16_t cog;
- int16_t mag_var;
- int16_t climb_rate;
- int16_t heading_rate;
- uint32_t h_error;
- uint32_t v_error;
- uint32_t t_error;
- uint16_t h_v_error;
-
-#define get_u8(u) u = (msg[off]); off+= 1
-#define get_u16(u) u = (msg[off] << 8) | (msg[off + 1]); off+= 2
-#define get_u32(u) u = (msg[off] << 24) | (msg[off + 1] << 16) | (msg[off+2] << 8) | (msg[off+3]); off+= 4
-
- get_u8(id);
- get_u16(nav_valid);
- get_u16(nav_type);
- get_u16(week);
- get_u32(tow);
- get_u16(year);
- get_u8(month);
- get_u8(day);
- get_u8(hour);
- get_u8(minute);
- get_u16(second);
- get_u32(sat_list);
- get_u32(lat);
- get_u32(lon);
- get_u32(alt_ell);
- get_u32(alt_msl);
- get_u8(datum);
- get_u16(sog);
- get_u16(cog);
- get_u16(mag_var);
- get_u16(climb_rate);
- get_u16(heading_rate);
- get_u32(h_error);
- get_u32(v_error);
- get_u32(t_error);
- get_u16(h_v_error);
-
-
- printf ("Geodetic Navigation Data (41):\n");
- printf ("\tNav valid %04x\n", nav_valid);
- printf ("\tNav type %04x\n", nav_type);
- printf ("\tWeek %5d", week);
- printf (" TOW %9d", tow);
- printf (" %4d-%2d-%2d %02d:%02d:%07.4f\n",
- year, month, day,
- hour, minute, second / 1000.0);
- printf ("\tsats: %08x\n", sat_list);
- printf ("\tlat: %g", lat / 1.0e7);
- printf (" lon: %g", lon / 1.0e7);
- printf (" alt_ell: %g", alt_ell / 100.0);
- printf (" alt_msll: %g", alt_msl / 100.0);
- printf (" datum: %d\n", datum);
- printf ("\tground speed: %g", sog / 100.0);
- printf (" course: %g", cog / 100.0);
- printf (" climb: %g", climb_rate / 100.0);
- printf (" heading rate: %g\n", heading_rate / 100.0);
- printf ("\th error: %g", h_error / 100.0);
- printf (" v error: %g", v_error / 100.0);
- printf (" t error: %g", t_error / 100.0);
- printf (" h vel error: %g\n", h_v_error / 100.0);
- break;
- }
- case 4: {
- int off = 4;
- uint8_t id;
- int16_t gps_week;
- uint32_t gps_tow;
- uint8_t channels;
- int j, k;
-
- get_u8(id);
- get_u16(gps_week);
- get_u32(gps_tow);
- get_u8(channels);
-
- printf ("Measured Tracker Data (4):\n");
- printf ("GPS week: %d\n", gps_week);
- printf ("GPS time of week: %d\n", gps_tow);
- printf ("channels: %d\n", channels);
- for (j = 0; j < 12; j++) {
- uint8_t svid, azimuth, elevation;
- uint16_t state;
- uint8_t c_n[10];
- get_u8(svid);
- get_u8(azimuth);
- get_u8(elevation);
- get_u16(state);
- for (k = 0; k < 10; k++) {
- get_u8(c_n[k]);
- }
- printf ("Sat %3d:", svid);
- printf (" aziumuth: %6.1f", azimuth * 1.5);
- printf (" elevation: %6.1f", elevation * 0.5);
- printf (" state: 0x%02x", state);
- printf (" c_n:");
- for (k = 0; k < 10; k++)
- printf(" %3d", c_n[k]);
- if (state & SIRF_SAT_STATE_ACQUIRED)
- printf(" acq,");
- if (state & SIRF_SAT_STATE_CARRIER_PHASE_VALID)
- printf(" car,");
- if (state & SIRF_SAT_BIT_SYNC_COMPLETE)
- printf(" bit,");
- if (state & SIRF_SAT_SUBFRAME_SYNC_COMPLETE)
- printf(" sub,");
- if (state & SIRF_SAT_CARRIER_PULLIN_COMPLETE)
- printf(" pullin,");
- if (state & SIRF_SAT_CODE_LOCKED)
- printf(" code,");
- if (state & SIRF_SAT_ACQUISITION_FAILED)
- printf(" fail,");
- if (state & SIRF_SAT_EPHEMERIS_AVAILABLE)
- printf(" ephem,");
- printf ("\n");
- }
- break;
- }
- default:
- return;
- printf ("%s %4d:", from, encoded_len);
- for (i = 4; i < len - 4; i++) {
- if (((i - 4) & 0xf) == 0)
- printf("\n ");
- printf (" %3d", msg[i]);
- }
- printf ("\n");
- }
-}
-
-static uint8_t skytraq_message[4096];
-static int skytraq_message_len;
-static uint8_t skytraq_in_message[4096];
-static int skytraq_in_len;
-
-char
-ao_serial_getchar(void)
-{
- char c;
- uint8_t uc;
-
- while (input_head == input_tail) {
- for (;;) {
- input_tail = read(ao_gps_fd, input_queue, QUEUE_LEN);
- if (input_tail < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
- perror ("getchar");
- exit (1);
- }
- input_head = 0;
- break;
- }
- }
- c = input_queue[input_head];
- input_head = (input_head + 1) % QUEUE_LEN;
- uc = c;
-// printf ("c: %02x %c\n", uc, uc);
- if (skytraq_in_len || uc == '$') {
- if (skytraq_in_len < 4096)
- skytraq_in_message[skytraq_in_len++] = uc;
- if (uc == 0x0a) {
- check_skytraq_message("recv", skytraq_in_message, skytraq_in_len);
- skytraq_in_len = 0;
- }
- }
- return c;
-}
-
-
-void
-ao_serial_putchar(char c)
-{
- int i;
- uint8_t uc = (uint8_t) c;
-
- if (skytraq_message_len || uc == 0xa0) {
- if (skytraq_message_len < 4096)
- skytraq_message[skytraq_message_len++] = uc;
- if (uc == 0x0a) {
- check_skytraq_message("send", skytraq_message, skytraq_message_len);
- skytraq_message_len = 0;
- }
- }
- for (;;) {
- i = write(ao_gps_fd, &c, 1);
- if (i == 1) {
- if ((uint8_t) c == 0xb3 || c == '\r') {
- static const struct timespec delay = {
- .tv_sec = 0,
- .tv_nsec = 100 * 1000 * 1000
- };
- tcdrain(ao_gps_fd);
-// nanosleep(&delay, NULL);
- }
- break;
- }
- if (i < 0 && (errno == EINTR || errno == EAGAIN))
- continue;
- perror("putchar");
- exit(1);
- }
-}
-
-#define AO_SERIAL_SPEED_4800 0
-#define AO_SERIAL_SPEED_9600 1
-#define AO_SERIAL_SPEED_57600 2
-
-static void
-ao_serial_set_speed(uint8_t speed)
-{
- int fd = ao_gps_fd;
- struct termios termios;
-
- tcdrain(fd);
- tcgetattr(fd, &termios);
- switch (speed) {
- case AO_SERIAL_SPEED_4800:
- cfsetspeed(&termios, B4800);
- break;
- case AO_SERIAL_SPEED_9600:
- cfsetspeed(&termios, B38400);
- break;
- case AO_SERIAL_SPEED_57600:
- cfsetspeed(&termios, B57600);
- break;
- }
- tcsetattr(fd, TCSAFLUSH, &termios);
- tcflush(fd, TCIFLUSH);
-}
-
-#define ao_time() 0
-
-#include "ao_gps_print.c"
-#include "ao_gps_skytraq.c"
-
-void
-ao_dump_state(void *wchan)
-{
- double lat, lon;
- int i;
- if (wchan == &ao_gps_data)
- ao_gps_print(&ao_gps_data);
- else
- ao_gps_tracking_print(&ao_gps_tracking_data);
- putchar('\n');
- return;
-}
-
-int
-ao_gps_open(const char *tty)
-{
- struct termios termios;
- int fd;
-
- fd = open (tty, O_RDWR);
- if (fd < 0)
- return -1;
-
- tcgetattr(fd, &termios);
- cfmakeraw(&termios);
- cfsetspeed(&termios, B4800);
- tcsetattr(fd, TCSAFLUSH, &termios);
-
- tcdrain(fd);
- tcflush(fd, TCIFLUSH);
- return fd;
-}
-
-#include <getopt.h>
-
-static const struct option options[] = {
- { .name = "tty", .has_arg = 1, .val = 'T' },
- { 0, 0, 0, 0},
-};
-
-static void usage(char *program)
-{
- fprintf(stderr, "usage: %s [--tty <tty-name>]\n", program);
- exit(1);
-}
-
-int
-main (int argc, char **argv)
-{
- char *tty = "/dev/ttyUSB0";
- int c;
-
- while ((c = getopt_long(argc, argv, "T:", options, NULL)) != -1) {
- switch (c) {
- case 'T':
- tty = optarg;
- break;
- default:
- usage(argv[0]);
- break;
- }
- }
- ao_gps_fd = ao_gps_open(tty);
- if (ao_gps_fd < 0) {
- perror (tty);
- exit (1);
- }
- ao_gps();
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#define _GNU_SOURCE
-
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define AO_ADC_RING 64
-#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1))
-#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1))
-
-/*
- * One set of samples read from the A/D converter
- */
-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 __pdata
-#define __data
-#define __xdata
-#define __code
-#define __reentrant
-
-enum ao_flight_state {
- ao_flight_startup = 0,
- ao_flight_idle = 1,
- ao_flight_pad = 2,
- ao_flight_boost = 3,
- ao_flight_fast = 4,
- ao_flight_coast = 5,
- ao_flight_drogue = 6,
- ao_flight_main = 7,
- ao_flight_landed = 8,
- ao_flight_invalid = 9
-};
-
-struct ao_adc ao_adc_ring[AO_ADC_RING];
-uint8_t ao_adc_head;
-
-#define ao_led_on(l)
-#define ao_led_off(l)
-#define ao_timer_set_adc_interval(i)
-#define ao_wakeup(wchan) ao_dump_state(wchan)
-#define ao_cmd_register(c)
-#define ao_usb_disable()
-#define ao_telemetry_set_interval(x)
-#define ao_delay(x)
-
-enum ao_igniter {
- ao_igniter_drogue = 0,
- ao_igniter_main = 1
-};
-
-void
-ao_ignite(enum ao_igniter igniter)
-{
- printf ("ignite %s\n", igniter == ao_igniter_drogue ? "drogue" : "main");
-}
-
-struct ao_task {
- int dummy;
-};
-
-#define ao_add_task(t,f,n)
-
-#define ao_log_start()
-#define ao_log_stop()
-
-#define AO_MS_TO_TICKS(ms) ((ms) / 10)
-#define AO_SEC_TO_TICKS(s) ((s) * 100)
-
-#define AO_FLIGHT_TEST
-
-struct ao_adc ao_adc_static;
-
-FILE *emulator_in;
-
-void
-ao_dump_state(void *wchan);
-
-void
-ao_sleep(void *wchan);
-
-const char const * const ao_state_names[] = {
- "startup", "idle", "pad", "boost", "fast",
- "coast", "drogue", "main", "landed", "invalid"
-};
-
-struct ao_cmds {
- void (*func)(void);
- const char *help;
-};
-
-
-struct ao_config {
- uint16_t main_deploy;
- int16_t accel_zero_g;
-};
-
-#define ao_config_get()
-
-struct ao_config ao_config = { 250, 16000 };
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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 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
-ao_ignite(enum ao_igniter igniter) __critical
-{
- ao_ignition[igniter].request = 1;
- ao_wakeup(&ao_ignition);
-}
-
-enum ao_igniter_status
-ao_igniter_status(enum ao_igniter igniter)
-{
- __xdata struct ao_adc adc;
- __pdata int16_t value;
- __pdata uint8_t request, firing, fired;
-
- __critical {
- ao_adc_get(&adc);
- request = ao_ignition[igniter].request;
- fired = ao_ignition[igniter].fired;
- firing = ao_ignition[igniter].firing;
- }
- if (firing || (request && !fired))
- return ao_igniter_active;
-
- value = (AO_IGNITER_CLOSED>>1);
- switch (igniter) {
- case ao_igniter_drogue:
- value = adc.sense_d;
- break;
- case ao_igniter_main:
- value = adc.sense_m;
- 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_igniter_fire(enum ao_igniter igniter) __critical
-{
- ao_ignition[igniter].firing = 1;
- switch(ao_config.ignite_mode) {
- case AO_IGNITE_MODE_DUAL:
- switch (igniter) {
- case ao_igniter_drogue:
- AO_IGNITER_DROGUE = 1;
- ao_delay(AO_IGNITER_FIRE_TIME);
- AO_IGNITER_DROGUE = 0;
- break;
- case ao_igniter_main:
- AO_IGNITER_MAIN = 1;
- ao_delay(AO_IGNITER_FIRE_TIME);
- AO_IGNITER_MAIN = 0;
- break;
- }
- break;
- case AO_IGNITE_MODE_APOGEE:
- switch (igniter) {
- case ao_igniter_drogue:
- AO_IGNITER_DROGUE = 1;
- ao_delay(AO_IGNITER_FIRE_TIME);
- AO_IGNITER_DROGUE = 0;
- ao_delay(AO_IGNITER_CHARGE_TIME);
- AO_IGNITER_MAIN = 1;
- ao_delay(AO_IGNITER_FIRE_TIME);
- AO_IGNITER_MAIN = 0;
- break;
- }
- break;
- case AO_IGNITE_MODE_MAIN:
- switch (igniter) {
- case ao_igniter_main:
- AO_IGNITER_DROGUE = 1;
- ao_delay(AO_IGNITER_FIRE_TIME);
- AO_IGNITER_DROGUE = 0;
- ao_delay(AO_IGNITER_CHARGE_TIME);
- AO_IGNITER_MAIN = 1;
- ao_delay(AO_IGNITER_FIRE_TIME);
- AO_IGNITER_MAIN = 0;
- break;
- }
- break;
- }
- ao_ignition[igniter].firing = 0;
-}
-
-void
-ao_igniter(void)
-{
- __xdata enum ao_ignter igniter;
-
- ao_config_get();
- for (;;) {
- ao_sleep(&ao_ignition);
- for (igniter = ao_igniter_drogue; igniter <= ao_igniter_main; igniter++) {
- if (ao_ignition[igniter].request && !ao_ignition[igniter].fired) {
- if (igniter == ao_igniter_drogue && ao_config.apogee_delay)
- ao_delay(AO_SEC_TO_TICKS(ao_config.apogee_delay));
-
- ao_igniter_fire(igniter);
- ao_delay(AO_IGNITER_CHARGE_TIME);
- ao_ignition[igniter].fired = 1;
- }
- }
- }
-}
-
-void
-ao_ignite_manual(void)
-{
- ao_cmd_white();
- if (!ao_match_word("DoIt"))
- return;
- ao_cmd_white();
- if (ao_cmd_lex_c == 'm') {
- if(ao_match_word("main"))
- ao_igniter_fire(ao_igniter_main);
- } else {
- if(ao_match_word("drogue"))
- ao_igniter_fire(ao_igniter_drogue);
- }
-}
-
-static __code char * __code igniter_status_names[] = {
- "unknown", "ready", "active", "open"
-};
-
-void
-ao_ignite_print_status(enum ao_igniter igniter, __code char *name) __reentrant
-{
- enum ao_igniter_status status = ao_igniter_status(igniter);
- printf("Igniter: %6s Status: %s\n",
- name,
- igniter_status_names[status]);
-}
-
-void
-ao_ignite_test(void)
-{
- ao_ignite_print_status(ao_igniter_drogue, "drogue");
- ao_ignite_print_status(ao_igniter_main, "main");
-}
-
-__code struct ao_cmds ao_ignite_cmds[] = {
- { ao_ignite_manual, "i <key> {main|drogue}\0Fire igniter. <key> is doit with D&I" },
- { ao_ignite_test, "t\0Test igniter" },
- { 0, NULL },
-};
-
-__xdata struct ao_task ao_igniter_task;
-
-void
-ao_ignite_set_pins(void)
-{
- AO_IGNITER_DROGUE = 0;
- AO_IGNITER_MAIN = 0;
- AO_IGNITER_DIR |= AO_IGNITER_DROGUE_BIT | AO_IGNITER_MAIN_BIT;
-}
-
-void
-ao_igniter_init(void)
-{
- ao_ignite_set_pins();
- ao_cmd_register(&ao_ignite_cmds[0]);
- ao_add_task(&ao_igniter_task, ao_igniter, "igniter");
-}
+++ /dev/null
-/*
- * Copyright © 2011 Anthony Towns <aj@erisian.com.au>
- *
- * 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 "cc1111.h"
-
-#define ENDOFCODE (CODESIZE)
-#define AO_INTFLASH_BLOCK 1024
-#define AO_INTFLASH_BLOCKS ((0x8000 - ENDOFCODE)/AO_INTFLASH_BLOCK)
-#define AO_INTFLASH_SIZE (AO_INTFLASH_BLOCK * AO_INTFLASH_BLOCKS)
-#define AO_INTFLASH_LOCATION (0x8000 - AO_INTFLASH_SIZE)
-
-/*
- * 21000 * 24e6
- * FWT = ------------
- * 16e9
- *
- * = 31.5
- *
- * Round up and use 32
- */
-
-#define FLASH_TIMING 0x20
-
-#if AO_INTFLASH_BLOCKS < 2
-#error "Too few pages"
-#endif
-
-#if AO_INFTLASH_LOCATION % 1024 != 0
-#error "Pages aren't aligned properly"
-#endif
-
-__xdata __at(AO_INTFLASH_LOCATION) uint8_t ao_intflash[AO_INTFLASH_SIZE];
-
-/* Total bytes of available storage */
-__pdata uint32_t ao_storage_total = sizeof(ao_intflash);
-
-/* Block size - device is erased in these units. */
-__pdata uint32_t ao_storage_block = AO_INTFLASH_BLOCK;
-
-/* Byte offset of config block. Will be ao_storage_block bytes long */
-__pdata uint32_t ao_storage_config = sizeof(ao_intflash) - AO_INTFLASH_BLOCK;
-
-/* Storage unit size - device reads and writes must be within blocks of this size. */
-__pdata uint16_t ao_storage_unit = AO_INTFLASH_BLOCK;
-
-__xdata static uint8_t ao_intflash_dma_done;
-static uint8_t ao_intflash_dma;
-
-/*
- * The internal flash chip is arranged in 1kB sectors; the
- * chip cannot erase in units smaller than that.
- *
- * Writing happens in units of 2 bytes and
- * can only change bits from 1 to 0. So, you can rewrite
- * the same contents, or append to an existing page easily enough
- */
-
-/*
- * Erase the specified sector
- */
-uint8_t
-ao_storage_erase(uint32_t pos) __reentrant
-{
- uint16_t addr;
-
- if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total)
- return 0;
-
- addr = ((uint16_t)(ao_intflash + pos) >> 1);
-
- FADDRH = addr >> 8;
- FADDRL = addr;
-
- __critical {
- _asm
- .even
- orl _FCTL, #FCTL_ERASE; ; FCTL |= FCTL_ERASE
- nop ; Required, see datasheet.
- _endasm;
- }
-
- return 1;
-}
-
-/*
- * Write to flash
- */
-
-static void
-ao_intflash_write_aligned(uint16_t pos, __xdata void *d, uint16_t len) __reentrant
-{
- pos = ((uint16_t) ao_intflash + pos) >> 1;
-
- ao_dma_set_transfer(ao_intflash_dma,
- d,
- &FWDATAXADDR,
- len,
- DMA_CFG0_WORDSIZE_8 |
- DMA_CFG0_TMODE_SINGLE |
- DMA_CFG0_TRIGGER_FLASH,
- DMA_CFG1_SRCINC_1 |
- DMA_CFG1_DESTINC_0 |
- DMA_CFG1_PRIORITY_HIGH);
-
- FADDRH = pos >> 8;
- FADDRL = pos;
-
- ao_dma_start(ao_intflash_dma);
-
- __critical {
- _asm
- .even
- orl _FCTL, #FCTL_WRITE; ; FCTL |= FCTL_WRITE
- nop
- _endasm;
- }
-}
-
-static void
-ao_intflash_write_byte(uint16_t pos, uint8_t byte) __reentrant
-{
- static __xdata uint8_t b[2];
-
- if (pos & 1) {
- b[0] = 0xff;
- b[1] = byte;
- } else {
- b[0] = byte;
- b[1] = 0xff;
- }
- ao_intflash_write_aligned(pos, b, 2);
-}
-
-uint8_t
-ao_storage_device_write(uint32_t pos32, __xdata void *v, uint16_t len) __reentrant
-{
- uint16_t pos = pos32;
- __xdata uint8_t *d = v;
- uint8_t oddlen;
-
- if (pos >= ao_storage_total || pos + len > ao_storage_total)
- return 0;
- if (len == 0)
- return 1;
-
- if (pos & 1) {
- ao_intflash_write_byte(pos++, *d++);
- len--;
- }
- oddlen = len & 1;
- len -= oddlen;
- if (len)
- ao_intflash_write_aligned(pos, d, len);
- if (oddlen)
- ao_intflash_write_byte(pos + len, d[len]);
-
- return 1;
-}
-
-/*
- * Read from flash
- */
-uint8_t
-ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
-{
- if (pos >= ao_storage_total || pos + len > ao_storage_total)
- return 0;
- memcpy(d, ao_intflash+pos, len);
- return 1;
-}
-
-void
-ao_storage_flush(void) __reentrant
-{
-}
-
-void
-ao_storage_setup(void)
-{
-}
-
-void
-ao_storage_device_info(void) __reentrant
-{
- printf ("Using internal flash, starting at 0x%04x\n", AO_INTFLASH_LOCATION);
-}
-
-void
-ao_storage_device_init(void)
-{
- ao_intflash_dma = ao_dma_alloc(&ao_intflash_dma_done);
-
- FWT = FLASH_TIMING;
-}
+++ /dev/null
-/*
- * 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_FLIGHT_TEST
-#include "ao.h"
-#endif
-
-#include "ao_kalman.h"
-
-static __pdata int32_t ao_k_height;
-static __pdata int32_t ao_k_speed;
-static __pdata int32_t ao_k_accel;
-
-#define AO_K_STEP_100 to_fix16(0.01)
-#define AO_K_STEP_2_2_100 to_fix16(0.00005)
-
-#define AO_K_STEP_10 to_fix16(0.1)
-#define AO_K_STEP_2_2_10 to_fix16(0.005)
-
-#define AO_K_STEP_1 to_fix16(1)
-#define AO_K_STEP_2_2_1 to_fix16(0.5)
-
-__pdata int16_t ao_height;
-__pdata int16_t ao_speed;
-__pdata int16_t ao_accel;
-__pdata int16_t ao_max_height;
-static __pdata int32_t ao_avg_height_scaled;
-__pdata int16_t ao_avg_height;
-
-__pdata int16_t ao_error_h;
-__pdata int16_t ao_error_h_sq_avg;
-
-#if HAS_ACCEL
-__pdata int16_t ao_error_a;
-#endif
-
-static void
-ao_kalman_predict(void)
-{
-#ifdef AO_FLIGHT_TEST
- if (ao_sample_tick - ao_sample_prev_tick > 50) {
- ao_k_height += ((int32_t) ao_speed * AO_K_STEP_1 +
- (int32_t) ao_accel * AO_K_STEP_2_2_1) >> 4;
- ao_k_speed += (int32_t) ao_accel * AO_K_STEP_1;
-
- return;
- }
- if (ao_sample_tick - ao_sample_prev_tick > 5) {
- ao_k_height += ((int32_t) ao_speed * AO_K_STEP_10 +
- (int32_t) ao_accel * AO_K_STEP_2_2_10) >> 4;
- ao_k_speed += (int32_t) ao_accel * AO_K_STEP_10;
-
- return;
- }
- if (ao_flight_debug) {
- printf ("predict speed %g + (%g * %g) = %g\n",
- ao_k_speed / (65536.0 * 16.0), ao_accel / 16.0, AO_K_STEP_100 / 65536.0,
- (ao_k_speed + (int32_t) ao_accel * AO_K_STEP_100) / (65536.0 * 16.0));
- }
-#endif
- ao_k_height += ((int32_t) ao_speed * AO_K_STEP_100 +
- (int32_t) ao_accel * AO_K_STEP_2_2_100) >> 4;
- ao_k_speed += (int32_t) ao_accel * AO_K_STEP_100;
-}
-
-static void
-ao_kalman_err_height(void)
-{
- int16_t e;
- int16_t height_distrust;
-#if HAS_ACCEL
- int16_t speed_distrust;
-#endif
-
- ao_error_h = ao_sample_height - (int16_t) (ao_k_height >> 16);
-
- e = ao_error_h;
- if (e < 0)
- e = -e;
- if (e > 127)
- e = 127;
-#if HAS_ACCEL
- ao_error_h_sq_avg -= ao_error_h_sq_avg >> 2;
- ao_error_h_sq_avg += (e * e) >> 2;
-#else
- ao_error_h_sq_avg -= ao_error_h_sq_avg >> 4;
- ao_error_h_sq_avg += (e * e) >> 4;
-#endif
-
- if (ao_flight_state >= ao_flight_drogue)
- return;
- height_distrust = ao_sample_alt - AO_MAX_BARO_HEIGHT;
-#if HAS_ACCEL
- /* speed is stored * 16, but we need to ramp between 200 and 328, so
- * we want to multiply by 2. The result is a shift by 3.
- */
- speed_distrust = (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) >> (4 - 1);
- if (speed_distrust <= 0)
- speed_distrust = 0;
- else if (speed_distrust > height_distrust)
- height_distrust = speed_distrust;
-#endif
- if (height_distrust > 0) {
-#ifdef AO_FLIGHT_TEST
- int old_ao_error_h = ao_error_h;
-#endif
- if (height_distrust > 0x100)
- height_distrust = 0x100;
- ao_error_h = (int16_t) (((int32_t) ao_error_h * (0x100 - height_distrust)) >> 8);
-#ifdef AO_FLIGHT_TEST
- if (ao_flight_debug) {
- printf("over height %g over speed %g distrust: %g height: error %d -> %d\n",
- (double) (ao_sample_alt - AO_MAX_BARO_HEIGHT),
- (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) / 16.0,
- height_distrust / 256.0,
- old_ao_error_h, ao_error_h);
- }
-#endif
- }
-}
-
-static void
-ao_kalman_correct_baro(void)
-{
- ao_kalman_err_height();
-#ifdef AO_FLIGHT_TEST
- if (ao_sample_tick - ao_sample_prev_tick > 50) {
- ao_k_height += (int32_t) AO_BARO_K0_1 * ao_error_h;
- ao_k_speed += (int32_t) AO_BARO_K1_1 * ao_error_h;
- ao_k_accel += (int32_t) AO_BARO_K2_1 * ao_error_h;
- return;
- }
- if (ao_sample_tick - ao_sample_prev_tick > 5) {
- ao_k_height += (int32_t) AO_BARO_K0_10 * ao_error_h;
- ao_k_speed += (int32_t) AO_BARO_K1_10 * ao_error_h;
- ao_k_accel += (int32_t) AO_BARO_K2_10 * ao_error_h;
- return;
- }
-#endif
- ao_k_height += (int32_t) AO_BARO_K0_100 * ao_error_h;
- ao_k_speed += (int32_t) AO_BARO_K1_100 * ao_error_h;
- ao_k_accel += (int32_t) AO_BARO_K2_100 * ao_error_h;
-}
-
-#if HAS_ACCEL
-
-static void
-ao_kalman_err_accel(void)
-{
- int32_t accel;
-
- accel = (ao_ground_accel - ao_sample_accel) * ao_accel_scale;
-
- /* Can't use ao_accel here as it is the pre-prediction value still */
- ao_error_a = (accel - ao_k_accel) >> 16;
-}
-
-static void
-ao_kalman_correct_both(void)
-{
- ao_kalman_err_height();
- ao_kalman_err_accel();
-
-#ifdef AO_FLIGHT_TEST
- if (ao_sample_tick - ao_sample_prev_tick > 50) {
- if (ao_flight_debug) {
- printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
- ao_k_speed / (65536.0 * 16.0),
- (double) ao_error_h, AO_BOTH_K10_1 / 65536.0,
- (double) ao_error_a, AO_BOTH_K11_1 / 65536.0,
- (ao_k_speed +
- (int32_t) AO_BOTH_K10_1 * ao_error_h +
- (int32_t) AO_BOTH_K11_1 * ao_error_a) / (65536.0 * 16.0));
- }
- ao_k_height +=
- (int32_t) AO_BOTH_K00_1 * ao_error_h +
- (int32_t) AO_BOTH_K01_1 * ao_error_a;
- ao_k_speed +=
- (int32_t) AO_BOTH_K10_1 * ao_error_h +
- (int32_t) AO_BOTH_K11_1 * ao_error_a;
- ao_k_accel +=
- (int32_t) AO_BOTH_K20_1 * ao_error_h +
- (int32_t) AO_BOTH_K21_1 * ao_error_a;
- return;
- }
- if (ao_sample_tick - ao_sample_prev_tick > 5) {
- if (ao_flight_debug) {
- printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
- ao_k_speed / (65536.0 * 16.0),
- (double) ao_error_h, AO_BOTH_K10_10 / 65536.0,
- (double) ao_error_a, AO_BOTH_K11_10 / 65536.0,
- (ao_k_speed +
- (int32_t) AO_BOTH_K10_10 * ao_error_h +
- (int32_t) AO_BOTH_K11_10 * ao_error_a) / (65536.0 * 16.0));
- }
- ao_k_height +=
- (int32_t) AO_BOTH_K00_10 * ao_error_h +
- (int32_t) AO_BOTH_K01_10 * ao_error_a;
- ao_k_speed +=
- (int32_t) AO_BOTH_K10_10 * ao_error_h +
- (int32_t) AO_BOTH_K11_10 * ao_error_a;
- ao_k_accel +=
- (int32_t) AO_BOTH_K20_10 * ao_error_h +
- (int32_t) AO_BOTH_K21_10 * ao_error_a;
- return;
- }
- if (ao_flight_debug) {
- printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
- ao_k_speed / (65536.0 * 16.0),
- (double) ao_error_h, AO_BOTH_K10_100 / 65536.0,
- (double) ao_error_a, AO_BOTH_K11_100 / 65536.0,
- (ao_k_speed +
- (int32_t) AO_BOTH_K10_100 * ao_error_h +
- (int32_t) AO_BOTH_K11_100 * ao_error_a) / (65536.0 * 16.0));
- }
-#endif
- ao_k_height +=
- (int32_t) AO_BOTH_K00_100 * ao_error_h +
- (int32_t) AO_BOTH_K01_100 * ao_error_a;
- ao_k_speed +=
- (int32_t) AO_BOTH_K10_100 * ao_error_h +
- (int32_t) AO_BOTH_K11_100 * ao_error_a;
- ao_k_accel +=
- (int32_t) AO_BOTH_K20_100 * ao_error_h +
- (int32_t) AO_BOTH_K21_100 * ao_error_a;
-}
-
-#ifdef FORCE_ACCEL
-static void
-ao_kalman_correct_accel(void)
-{
- ao_kalman_err_accel();
-
- if (ao_sample_tick - ao_sample_prev_tick > 5) {
- ao_k_height +=(int32_t) AO_ACCEL_K0_10 * ao_error_a;
- ao_k_speed += (int32_t) AO_ACCEL_K1_10 * ao_error_a;
- ao_k_accel += (int32_t) AO_ACCEL_K2_10 * ao_error_a;
- return;
- }
- ao_k_height += (int32_t) AO_ACCEL_K0_100 * ao_error_a;
- ao_k_speed += (int32_t) AO_ACCEL_K1_100 * ao_error_a;
- ao_k_accel += (int32_t) AO_ACCEL_K2_100 * ao_error_a;
-}
-#endif
-#endif /* HAS_ACCEL */
-
-void
-ao_kalman(void)
-{
- ao_kalman_predict();
-#if HAS_ACCEL
- if (ao_flight_state <= ao_flight_coast) {
-#ifdef FORCE_ACCEL
- ao_kalman_correct_accel();
-#else
- ao_kalman_correct_both();
-#endif
- } else
-#endif
- ao_kalman_correct_baro();
- ao_height = from_fix(ao_k_height);
- ao_speed = from_fix(ao_k_speed);
- ao_accel = from_fix(ao_k_accel);
- if (ao_height > ao_max_height)
- ao_max_height = ao_height;
- ao_avg_height_scaled = ao_avg_height_scaled - ao_avg_height + ao_sample_height;
-#ifdef AO_FLIGHT_TEST
- if (ao_sample_tick - ao_sample_prev_tick > 50)
- ao_avg_height = (ao_avg_height_scaled + 1) >> 1;
- else if (ao_sample_tick - ao_sample_prev_tick > 5)
- ao_avg_height = (ao_avg_height_scaled + 7) >> 4;
- else
-#endif
- ao_avg_height = (ao_avg_height_scaled + 63) >> 7;
-#ifdef AO_FLIGHT_TEST
- ao_sample_prev_tick = ao_sample_tick;
-#endif
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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;
-
-void
-ao_led_on(uint8_t colors)
-{
- P1 |= (colors & ao_led_enable);
-}
-
-void
-ao_led_off(uint8_t colors)
-{
- P1 &= ~(colors & ao_led_enable);
-}
-
-void
-ao_led_set(uint8_t colors)
-{
- P1 = (P1 & ~(ao_led_enable)) | (colors & ao_led_enable);
-}
-
-void
-ao_led_toggle(uint8_t colors)
-{
- P1 ^= (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;
- P1SEL &= ~enable;
- P1 &= ~enable;
- P1DIR |= enable;
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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 uint32_t ao_log_current_pos;
-__pdata uint32_t ao_log_end_pos;
-__pdata uint32_t ao_log_start_pos;
-__xdata uint8_t ao_log_running;
-__pdata enum flight_state ao_log_state;
-__xdata uint16_t ao_flight_number;
-
-__code uint8_t ao_log_format = AO_LOG_FORMAT_FULL;
-
-void
-ao_log_flush(void)
-{
- ao_storage_flush();
-}
-
-/*
- * When erasing a flight log, make sure the config block
- * has an up-to-date version of the current flight number
- */
-
-struct ao_log_erase {
- uint8_t unused;
- uint16_t flight;
-};
-
-static __xdata struct ao_log_erase erase;
-
-#define LOG_MAX_ERASE 16
-
-static uint32_t
-ao_log_erase_pos(uint8_t i)
-{
- return i * sizeof (struct ao_log_erase) + AO_STORAGE_ERASE_LOG;
-}
-
-void
-ao_log_write_erase(uint8_t pos)
-{
- erase.unused = 0x00;
- erase.flight = ao_flight_number;
- ao_storage_write(ao_log_erase_pos(pos), &erase, sizeof (erase));
- ao_storage_flush();
-}
-
-static void
-ao_log_read_erase(uint8_t pos)
-{
- ao_storage_read(ao_log_erase_pos(pos), &erase, sizeof (erase));
-}
-
-
-static void
-ao_log_erase_mark(void)
-{
- uint8_t i;
-
- for (i = 0; i < LOG_MAX_ERASE; i++) {
- ao_log_read_erase(i);
- if (erase.unused == 0 && erase.flight == ao_flight_number)
- return;
- if (erase.unused == 0xff) {
- ao_log_write_erase(i);
- return;
- }
- }
- ao_config_put();
-}
-
-static uint8_t
-ao_log_slots()
-{
- return (uint8_t) (ao_storage_config / ao_config.flight_log_max);
-}
-
-uint32_t
-ao_log_pos(uint8_t slot)
-{
- return ((slot) * ao_config.flight_log_max);
-}
-
-static uint16_t
-ao_log_max_flight(void)
-{
- uint8_t log_slot;
- uint8_t log_slots;
- uint16_t log_flight;
- uint16_t max_flight = 0;
-
- /* Scan the log space looking for the biggest flight number */
- log_slots = ao_log_slots();
- for (log_slot = 0; log_slot < log_slots; log_slot++) {
- log_flight = ao_log_flight(log_slot);
- if (!log_flight)
- continue;
- if (max_flight == 0 || (int16_t) (log_flight - max_flight) > 0)
- max_flight = log_flight;
- }
- return max_flight;
-}
-
-void
-ao_log_scan(void) __reentrant
-{
- uint8_t log_slot;
- uint8_t log_slots;
- uint8_t log_want;
-
- ao_config_get();
-
- ao_flight_number = ao_log_max_flight();
- if (ao_flight_number)
- if (++ao_flight_number == 0)
- ao_flight_number = 1;
-
- /* Now look through the log of flight numbers from erase operations and
- * see if the last one is bigger than what we found above
- */
- for (log_slot = LOG_MAX_ERASE; log_slot-- > 0;) {
- ao_log_read_erase(log_slot);
- if (erase.unused == 0) {
- if (ao_flight_number == 0 ||
- (int16_t) (erase.flight - ao_flight_number) > 0)
- ao_flight_number = erase.flight;
- break;
- }
- }
- if (ao_flight_number == 0)
- ao_flight_number = 1;
-
- /* With a flight number in hand, find a place to write a new log,
- * use the target flight number to index the available log slots so
- * that we write logs to each spot about the same number of times.
- */
-
- /* Find a log slot for the next flight, if available */
- ao_log_current_pos = ao_log_end_pos = 0;
- log_slots = ao_log_slots();
- log_want = (ao_flight_number - 1) % log_slots;
- log_slot = log_want;
- do {
- if (ao_log_flight(log_slot) == 0) {
- ao_log_current_pos = ao_log_pos(log_slot);
- ao_log_end_pos = ao_log_current_pos + ao_config.flight_log_max;
- break;
- }
- if (++log_slot >= log_slots)
- log_slot = 0;
- } while (log_slot != log_want);
-
- ao_wakeup(&ao_flight_number);
-}
-
-void
-ao_log_start(void)
-{
- /* start logging */
- ao_log_running = 1;
- ao_wakeup(&ao_log_running);
-}
-
-void
-ao_log_stop(void)
-{
- ao_log_running = 0;
- ao_log_flush();
-}
-
-uint8_t
-ao_log_present(void)
-{
- return ao_log_max_flight() != 0;
-}
-
-uint8_t
-ao_log_full(void)
-{
- return ao_log_current_pos == ao_log_end_pos;
-}
-
-static __xdata struct ao_task ao_log_task;
-
-void
-ao_log_list(void) __reentrant
-{
- uint8_t slot;
- uint8_t slots;
- uint16_t flight;
-
- slots = ao_log_slots();
- for (slot = 0; slot < slots; slot++)
- {
- flight = ao_log_flight(slot);
- if (flight)
- printf ("flight %d start %x end %x\n",
- flight,
- (uint16_t) (ao_log_pos(slot) >> 8),
- (uint16_t) (ao_log_pos(slot+1) >> 8));
- }
- printf ("done\n");
-}
-
-void
-ao_log_delete(void) __reentrant
-{
- uint8_t slot;
- uint8_t slots;
-
- ao_cmd_decimal();
- if (ao_cmd_status != ao_cmd_success)
- return;
-
- slots = ao_log_slots();
- /* Look for the flight log matching the requested flight */
- if (ao_cmd_lex_i) {
- for (slot = 0; slot < slots; slot++) {
- if (ao_log_flight(slot) == ao_cmd_lex_i) {
- ao_log_erase_mark();
- ao_log_current_pos = ao_log_pos(slot);
- ao_log_end_pos = ao_log_current_pos + ao_config.flight_log_max;
- while (ao_log_current_pos < ao_log_end_pos) {
- uint8_t i;
- static __xdata uint8_t b;
-
- /*
- * Check to see if we've reached the end of
- * the used memory to avoid re-erasing the same
- * memory over and over again
- */
- for (i = 0; i < 16; i++) {
- if (ao_storage_read(ao_log_current_pos + i, &b, 1))
- if (b != 0xff)
- break;
- }
- if (i == 16)
- break;
- ao_storage_erase(ao_log_current_pos);
- ao_log_current_pos += ao_storage_block;
- }
- puts("Erased");
- return;
- }
- }
- }
- printf("No such flight: %d\n", ao_cmd_lex_i);
-}
-
-__code struct ao_cmds ao_log_cmds[] = {
- { ao_log_list, "l\0List flight logs" },
- { ao_log_delete, "d <flight-number>\0Delete flight" },
- { 0, NULL },
-};
-
-void
-ao_log_init(void)
-{
- ao_log_running = 0;
-
- /* For now, just log the flight starting at the begining of eeprom */
- ao_log_state = ao_flight_invalid;
-
- ao_cmd_register(&ao_log_cmds[0]);
-
- /* Create a task to log events to eeprom */
- ao_add_task(&ao_log_task, ao_log, "log");
-}
+++ /dev/null
-/*
- * 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"
-
-static __xdata uint8_t ao_log_mutex;
-static __xdata struct ao_log_record log;
-
-static uint8_t
-ao_log_csum(__xdata uint8_t *b) __reentrant
-{
- uint8_t sum = 0x5a;
- uint8_t i;
-
- for (i = 0; i < sizeof (struct ao_log_record); i++)
- sum += *b++;
- return -sum;
-}
-
-uint8_t
-ao_log_data(__xdata struct ao_log_record *log) __reentrant
-{
- uint8_t wrote = 0;
- /* set checksum */
- log->csum = 0;
- log->csum = ao_log_csum((__xdata uint8_t *) log);
- ao_mutex_get(&ao_log_mutex); {
- if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
- ao_log_stop();
- if (ao_log_running) {
- wrote = 1;
- ao_storage_write(ao_log_current_pos,
- log,
- sizeof (struct ao_log_record));
- ao_log_current_pos += sizeof (struct ao_log_record);
- }
- } ao_mutex_put(&ao_log_mutex);
- return wrote;
-}
-
-static uint8_t
-ao_log_dump_check_data(void)
-{
- if (ao_log_csum((uint8_t *) &log) != 0)
- return 0;
- return 1;
-}
-
-static __data uint8_t ao_log_adc_pos;
-
-/* a hack to make sure that ao_log_records fill the eeprom block in even units */
-typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_record))] ;
-
-#define AO_SENSOR_INTERVAL_ASCENT 1
-#define AO_SENSOR_INTERVAL_DESCENT 10
-#define AO_OTHER_INTERVAL 32
-
-void
-ao_log(void)
-{
- __pdata uint16_t next_sensor, next_other;
-
- ao_storage_setup();
-
- ao_log_scan();
-
- while (!ao_log_running)
- ao_sleep(&ao_log_running);
-
- log.type = AO_LOG_FLIGHT;
- log.tick = ao_sample_tick;
-#if HAS_ACCEL
- log.u.flight.ground_accel = ao_ground_accel;
-#endif
- log.u.flight.flight = ao_flight_number;
- ao_log_data(&log);
-
- /* Write the whole contents of the ring to the log
- * when starting up.
- */
- ao_log_adc_pos = ao_adc_ring_next(ao_sample_adc);
- next_other = next_sensor = ao_adc_ring[ao_log_adc_pos].tick;
- ao_log_state = ao_flight_startup;
- for (;;) {
- /* Write samples to EEPROM */
- while (ao_log_adc_pos != ao_sample_adc) {
- log.tick = ao_adc_ring[ao_log_adc_pos].tick;
- if ((int16_t) (log.tick - next_sensor) >= 0) {
- log.type = AO_LOG_SENSOR;
- log.u.sensor.accel = ao_adc_ring[ao_log_adc_pos].accel;
- log.u.sensor.pres = ao_adc_ring[ao_log_adc_pos].pres;
- ao_log_data(&log);
- if (ao_log_state <= ao_flight_coast)
- next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT;
- else
- next_sensor = log.tick + AO_SENSOR_INTERVAL_DESCENT;
- }
- if ((int16_t) (log.tick - next_other) >= 0) {
- log.type = AO_LOG_TEMP_VOLT;
- log.u.temp_volt.temp = ao_adc_ring[ao_log_adc_pos].temp;
- log.u.temp_volt.v_batt = ao_adc_ring[ao_log_adc_pos].v_batt;
- ao_log_data(&log);
- log.type = AO_LOG_DEPLOY;
- log.u.deploy.drogue = ao_adc_ring[ao_log_adc_pos].sense_d;
- log.u.deploy.main = ao_adc_ring[ao_log_adc_pos].sense_m;
- ao_log_data(&log);
- next_other = log.tick + AO_OTHER_INTERVAL;
- }
- ao_log_adc_pos = ao_adc_ring_next(ao_log_adc_pos);
- }
- /* Write state change to EEPROM */
- if (ao_flight_state != ao_log_state) {
- ao_log_state = ao_flight_state;
- log.type = AO_LOG_STATE;
- log.tick = ao_sample_tick;
- log.u.state.state = ao_log_state;
- log.u.state.reason = 0;
- ao_log_data(&log);
-
- if (ao_log_state == ao_flight_landed)
- ao_log_stop();
- }
-
- /* Wait for a while */
- ao_delay(AO_MS_TO_TICKS(100));
-
- /* Stop logging when told to */
- while (!ao_log_running)
- ao_sleep(&ao_log_running);
- }
-}
-
-uint16_t
-ao_log_flight(uint8_t slot)
-{
- if (!ao_storage_read(ao_log_pos(slot),
- &log,
- sizeof (struct ao_log_record)))
- return 0;
-
- if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
- return log.u.flight.flight;
- return 0;
-}
+++ /dev/null
-/*
- * 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
-ao_log_write_erase(uint8_t pos)
-{
- (void) pos;
-}
-
-uint8_t
-ao_log_present(void)
-{
- return 0;
-}
+++ /dev/null
-/*
- * 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"
-
-static __data uint16_t ao_log_tiny_interval;
-
-#define AO_LOG_TINY_INTERVAL_DEFAULT AO_MS_TO_TICKS(1000)
-#if USE_FAST_ASCENT_LOG
-#define AO_LOG_TINY_INTERVAL_ASCENT AO_MS_TO_TICKS(100)
-#define AO_PAD_RING 8
-#else
-#define AO_LOG_TINY_INTERVAL_ASCENT AO_LOG_TINY_INTERVAL_DEFAULT
-#define AO_PAD_RING 2
-#endif
-
-__code uint8_t ao_log_format = AO_LOG_FORMAT_TINY;
-
-void
-ao_log_tiny_set_interval(uint16_t ticks)
-{
- ao_log_tiny_interval = ticks;
-}
-
-
-static void ao_log_tiny_data(uint16_t d)
-{
- if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
- ao_log_stop();
- if (ao_log_running) {
- ao_storage_write(ao_log_current_pos, DATA_TO_XDATA(&d), 2);
- ao_log_current_pos += 2;
- }
-}
-
-static __xdata uint16_t ao_log_pad_ring[AO_PAD_RING];
-static __pdata uint8_t ao_log_pad_ring_pos;
-
-#define ao_pad_ring_next(n) (((n) + 1) & (AO_PAD_RING - 1))
-
-static void ao_log_tiny_queue(uint16_t d)
-{
- ao_log_pad_ring[ao_log_pad_ring_pos] = d;
- ao_log_pad_ring_pos = ao_pad_ring_next(ao_log_pad_ring_pos);
-}
-
-static void ao_log_tiny_start(void)
-{
- uint8_t p;
- uint16_t d;
-
- ao_log_tiny_data(ao_flight_number);
- ao_log_tiny_data(ao_ground_pres);
- p = ao_log_pad_ring_pos;
- do {
- d = ao_log_pad_ring[p];
- /*
- * ignore unwritten slots
- */
- if (d)
- ao_log_tiny_data(d);
- p = ao_pad_ring_next(p);
- } while (p != ao_log_pad_ring_pos);
-}
-
-void
-ao_log(void)
-{
- uint16_t last_time;
- uint16_t now;
- enum ao_flight_state ao_log_tiny_state;
- int32_t sum;
- int16_t count;
- uint8_t ao_log_adc;
- uint8_t ao_log_started = 0;
-
- ao_storage_setup();
-
- ao_log_scan();
-
- ao_log_tiny_state = ao_flight_invalid;
- ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT;
- sum = 0;
- count = 0;
- ao_log_adc = ao_sample_adc;
- last_time = ao_time();
- for (;;) {
-
- /*
- * Add in pending sample data
- */
- ao_sleep(DATA_TO_XDATA(&ao_sample_adc));
- while (ao_log_adc != ao_sample_adc) {
- sum += ao_adc_ring[ao_log_adc].pres;
- count++;
- ao_log_adc = ao_adc_ring_next(ao_log_adc);
- }
- if (ao_log_running) {
- if (!ao_log_started) {
- ao_log_tiny_start();
- ao_log_started = 1;
- }
- if (ao_flight_state != ao_log_tiny_state) {
- ao_log_tiny_data(ao_flight_state | 0x8000);
- ao_log_tiny_state = ao_flight_state;
- ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_DEFAULT;
-#if AO_LOG_TINY_INTERVAL_ASCENT != AO_LOG_TINY_INTERVAL_DEFAULT
- if (ao_log_tiny_state <= ao_flight_coast)
- ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT;
-#endif
- if (ao_log_tiny_state == ao_flight_landed)
- ao_log_stop();
- }
- }
-
- /* Stop logging when told to */
- if (!ao_log_running && ao_log_started)
- ao_exit();
-
- /*
- * Write out the sample when finished
- */
- now = ao_time();
- if ((int16_t) (now - (last_time + ao_log_tiny_interval)) >= 0 && count) {
- count = sum / count;
- if (ao_log_started)
- ao_log_tiny_data(count);
- else
- ao_log_tiny_queue(count);
- sum = 0;
- count = 0;
- last_time = now;
- }
- }
-}
-
-uint16_t
-ao_log_flight(uint8_t slot)
-{
- static __xdata uint16_t flight;
-
- (void) slot;
- ao_storage_read(0, &flight, 2);
- if (flight == 0xffff)
- flight = 0;
- return flight;
-}
+++ /dev/null
-/*
- * 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.
- */
-
-#include "ao.h"
-
-/* Total bytes of available storage */
-__pdata uint32_t ao_storage_total;
-
-/* Block size - device is erased in these units. At least 256 bytes */
-__pdata uint32_t ao_storage_block;
-
-/* Byte offset of config block. Will be ao_storage_block bytes long */
-__pdata uint32_t ao_storage_config;
-
-/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */
-__pdata uint16_t ao_storage_unit;
-
-/*
- * Each flash chip is arranged in 64kB sectors; the
- * chip cannot erase in units smaller than that.
- *
- * Writing happens in units of 256 byte pages and
- * can only change bits from 1 to 0. So, you can rewrite
- * the same contents, or append to an existing page easily enough
- */
-
-#define M25_WREN 0x06 /* Write Enable */
-#define M25_WRDI 0x04 /* Write Disable */
-#define M25_RDID 0x9f /* Read Identification */
-#define M25_RDSR 0x05 /* Read Status Register */
-#define M25_WRSR 0x01 /* Write Status Register */
-#define M25_READ 0x03 /* Read Data Bytes */
-#define M25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
-#define M25_PP 0x02 /* Page Program */
-#define M25_SE 0xd8 /* Sector Erase */
-#define M25_BE 0xc7 /* Bulk Erase */
-#define M25_DP 0xb9 /* Deep Power-down */
-
-/* RDID response */
-#define M25_MANUF_OFFSET 0
-#define M25_MEMORY_TYPE_OFFSET 1
-#define M25_CAPACITY_OFFSET 2
-#define M25_UID_OFFSET 3
-#define M25_CFI_OFFSET 4
-#define M25_RDID_LEN 4 /* that's all we need */
-
-#define M25_CAPACITY_128KB 0x11
-#define M25_CAPACITY_256KB 0x12
-#define M25_CAPACITY_512KB 0x13
-#define M25_CAPACITY_1MB 0x14
-#define M25_CAPACITY_2MB 0x15
-
-/*
- * Status register bits
- */
-
-#define M25_STATUS_SRWD (1 << 7) /* Status register write disable */
-#define M25_STATUS_BP_MASK (7 << 2) /* Block protect bits */
-#define M25_STATUS_BP_SHIFT (2)
-#define M25_STATUS_WEL (1 << 1) /* Write enable latch */
-#define M25_STATUS_WIP (1 << 0) /* Write in progress */
-
-/*
- * On teleterra, the m25 chip select pins are
- * wired on P0_0 through P0_3.
- */
-
-#if M25_MAX_CHIPS > 1
-static uint8_t ao_m25_size[M25_MAX_CHIPS]; /* number of sectors in each chip */
-static uint8_t ao_m25_pin[M25_MAX_CHIPS]; /* chip select pin for each chip */
-static uint8_t ao_m25_numchips; /* number of chips detected */
-#endif
-static uint8_t ao_m25_total; /* total sectors available */
-static uint8_t ao_m25_wip; /* write in progress */
-
-static __xdata uint8_t ao_m25_mutex;
-
-/*
- * This little array is abused to send and receive data. A particular
- * caution -- the read and write addresses are written into the last
- * three bytes of the array by ao_m25_set_page_address and then the
- * first byte is used by ao_m25_wait_wip and ao_m25_write_enable, neither
- * of which touch those last three bytes.
- */
-
-static __xdata uint8_t ao_m25_instruction[4];
-
-#define M25_SELECT(cs) ao_spi_get_mask(SPI_CS_PORT,cs)
-#define M25_DESELECT(cs) ao_spi_put_mask(SPI_CS_PORT,cs)
-
-#define M25_BLOCK_SHIFT 16
-#define M25_BLOCK 65536L
-#define M25_POS_TO_SECTOR(pos) ((uint8_t) ((pos) >> M25_BLOCK_SHIFT))
-#define M25_SECTOR_TO_POS(sector) (((uint32_t) (sector)) << M25_BLOCK_SHIFT)
-
-/*
- * Block until the specified chip is done writing
- */
-static void
-ao_m25_wait_wip(uint8_t cs)
-{
- if (ao_m25_wip & cs) {
- M25_SELECT(cs);
- ao_m25_instruction[0] = M25_RDSR;
- ao_spi_send(ao_m25_instruction, 1);
- do {
- ao_spi_recv(ao_m25_instruction, 1);
- } while (ao_m25_instruction[0] & M25_STATUS_WIP);
- M25_DESELECT(cs);
- ao_m25_wip &= ~cs;
- }
-}
-
-/*
- * Set the write enable latch so that page program and sector
- * erase commands will work. Also mark the chip as busy writing
- * so that future operations will block until the WIP bit goes off
- */
-static void
-ao_m25_write_enable(uint8_t cs)
-{
- M25_SELECT(cs);
- ao_m25_instruction[0] = M25_WREN;
- ao_spi_send(&ao_m25_instruction, 1);
- M25_DESELECT(cs);
- ao_m25_wip |= cs;
-}
-
-
-/*
- * Returns the number of 64kB sectors
- */
-static uint8_t
-ao_m25_read_capacity(uint8_t cs)
-{
- uint8_t capacity;
- M25_SELECT(cs);
- ao_m25_instruction[0] = M25_RDID;
- ao_spi_send(ao_m25_instruction, 1);
- ao_spi_recv(ao_m25_instruction, M25_RDID_LEN);
- M25_DESELECT(cs);
-
- /* Check to see if the chip is present */
- if (ao_m25_instruction[0] == 0xff)
- return 0;
- capacity = ao_m25_instruction[M25_CAPACITY_OFFSET];
-
- /* Sanity check capacity number */
- if (capacity < 0x11 || 0x1f < capacity)
- return 0;
- return 1 << (capacity - 0x10);
-}
-
-static uint8_t
-ao_m25_set_address(uint32_t pos)
-{
- uint8_t chip;
-#if M25_MAX_CHIPS > 1
- uint8_t size;
-
- for (chip = 0; chip < ao_m25_numchips; chip++) {
- size = ao_m25_size[chip];
- if (M25_POS_TO_SECTOR(pos) < size)
- break;
- pos -= M25_SECTOR_TO_POS(size);
- }
- if (chip == ao_m25_numchips)
- return 0xff;
-
- chip = ao_m25_pin[chip];
-#else
- chip = M25_CS_MASK;
-#endif
- ao_m25_wait_wip(chip);
-
- ao_m25_instruction[1] = pos >> 16;
- ao_m25_instruction[2] = pos >> 8;
- ao_m25_instruction[3] = pos;
- return chip;
-}
-
-/*
- * Scan the possible chip select lines
- * to see which flash chips are connected
- */
-static uint8_t
-ao_m25_scan(void)
-{
-#if M25_MAX_CHIPS > 1
- uint8_t pin, size;
-#endif
-
- if (ao_m25_total)
- return 1;
-
-#if M25_MAX_CHIPS > 1
- ao_m25_numchips = 0;
- for (pin = 1; pin != 0; pin <<= 1) {
- if (M25_CS_MASK & pin) {
- size = ao_m25_read_capacity(pin);
- if (size != 0) {
- ao_m25_size[ao_m25_numchips] = size;
- ao_m25_pin[ao_m25_numchips] = pin;
- ao_m25_total += size;
- ao_m25_numchips++;
- }
- }
- }
-#else
- ao_m25_total = ao_m25_read_capacity(M25_CS_MASK);
-#endif
- if (!ao_m25_total)
- return 0;
- ao_storage_total = M25_SECTOR_TO_POS(ao_m25_total);
- ao_storage_block = M25_BLOCK;
- ao_storage_config = ao_storage_total - M25_BLOCK;
- ao_storage_unit = 256;
- return 1;
-}
-
-/*
- * Erase the specified sector
- */
-uint8_t
-ao_storage_erase(uint32_t pos) __reentrant
-{
- uint8_t cs;
-
- if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total)
- return 0;
-
- ao_mutex_get(&ao_m25_mutex);
- ao_m25_scan();
-
- cs = ao_m25_set_address(pos);
-
- ao_m25_wait_wip(cs);
- ao_m25_write_enable(cs);
-
- ao_m25_instruction[0] = M25_SE;
- M25_SELECT(cs);
- ao_spi_send(ao_m25_instruction, 4);
- M25_DESELECT(cs);
- ao_m25_wip |= cs;
-
- ao_mutex_put(&ao_m25_mutex);
- return 1;
-}
-
-/*
- * Write to flash
- */
-uint8_t
-ao_storage_device_write(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
-{
- uint8_t cs;
-
- if (pos >= ao_storage_total || pos + len > ao_storage_total)
- return 0;
-
- ao_mutex_get(&ao_m25_mutex);
- ao_m25_scan();
-
- cs = ao_m25_set_address(pos);
- ao_m25_write_enable(cs);
-
- ao_m25_instruction[0] = M25_PP;
- M25_SELECT(cs);
- ao_spi_send(ao_m25_instruction, 4);
- ao_spi_send(d, len);
- M25_DESELECT(cs);
-
- ao_mutex_put(&ao_m25_mutex);
- return 1;
-}
-
-/*
- * Read from flash
- */
-uint8_t
-ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
-{
- uint8_t cs;
-
- if (pos >= ao_storage_total || pos + len > ao_storage_total)
- return 0;
- ao_mutex_get(&ao_m25_mutex);
- ao_m25_scan();
-
- cs = ao_m25_set_address(pos);
-
- /* No need to use the FAST_READ as we're running at only 8MHz */
- ao_m25_instruction[0] = M25_READ;
- M25_SELECT(cs);
- ao_spi_send(ao_m25_instruction, 4);
- ao_spi_recv(d, len);
- M25_DESELECT(cs);
-
- ao_mutex_put(&ao_m25_mutex);
- return 1;
-}
-
-void
-ao_storage_flush(void) __reentrant
-{
-}
-
-void
-ao_storage_setup(void)
-{
- ao_mutex_get(&ao_m25_mutex);
- ao_m25_scan();
- ao_mutex_put(&ao_m25_mutex);
-}
-
-void
-ao_storage_device_info(void) __reentrant
-{
- uint8_t cs;
-#if M25_MAX_CHIPS > 1
- uint8_t chip;
-#endif
-
- ao_mutex_get(&ao_m25_mutex);
- ao_m25_scan();
- ao_mutex_put(&ao_m25_mutex);
-
-#if M25_MAX_CHIPS > 1
- printf ("Detected chips %d size %d\n", ao_m25_numchips, ao_m25_total);
- for (chip = 0; chip < ao_m25_numchips; chip++)
- printf ("Flash chip %d select %02x size %d\n",
- chip, ao_m25_pin[chip], ao_m25_size[chip]);
-#else
- printf ("Detected chips 1 size %d\n", ao_m25_total);
-#endif
-
- printf ("Available chips:\n");
- for (cs = 1; cs != 0; cs <<= 1) {
- if ((M25_CS_MASK & cs) == 0)
- continue;
-
- ao_mutex_get(&ao_m25_mutex);
- M25_SELECT(cs);
- ao_m25_instruction[0] = M25_RDID;
- ao_spi_send(ao_m25_instruction, 1);
- ao_spi_recv(ao_m25_instruction, M25_RDID_LEN);
- M25_DESELECT(cs);
-
- printf ("Select %02x manf %02x type %02x cap %02x uid %02x\n",
- cs,
- ao_m25_instruction[M25_MANUF_OFFSET],
- ao_m25_instruction[M25_MEMORY_TYPE_OFFSET],
- ao_m25_instruction[M25_CAPACITY_OFFSET],
- ao_m25_instruction[M25_UID_OFFSET]);
- ao_mutex_put(&ao_m25_mutex);
- }
-}
-
-void
-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 */
- SPI_CS_SEL &= ~M25_CS_MASK; /* set CS pins as GPIO */
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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
-main(void)
-{
- ao_clock_init();
-
- /* Turn on the red LED until the system is stable */
- ao_led_init();
- 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_usb_init();
- ao_serial_init();
- ao_gps_init();
- ao_telemetry_init();
- ao_radio_init();
- ao_start_scheduler();
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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_telem.h"
-
-#if !HAS_MONITOR
-#error Must define HAS_MONITOR to 1
-#endif
-
-__xdata 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))
-
-__data uint8_t ao_monitor_head;
-
-void
-ao_monitor_get(void)
-{
- uint8_t size;
-
- for (;;) {
- switch (ao_monitoring) {
- case 0:
- ao_sleep(&ao_monitoring);
- continue;
- case AO_MONITORING_ORIG:
- size = sizeof (struct ao_telemetry_orig_recv);
- break;
- case AO_MONITORING_TINY:
- size = sizeof (struct ao_telemetry_tiny_recv);
- break;
- default:
- if (ao_monitoring > AO_MAX_TELEMETRY)
- ao_monitoring = AO_MAX_TELEMETRY;
- size = ao_monitoring;
- break;
- }
- if (!ao_radio_recv(&ao_monitor_ring[ao_monitor_head], size + 2))
- 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_put(void)
-{
- __xdata char callsign[AO_MAX_CALLSIGN+1];
-
- uint8_t ao_monitor_tail;
- uint8_t state;
- uint8_t sum, byte;
- int16_t rssi;
- __xdata union ao_monitor *m;
-
-#define recv_raw ((m->raw))
-#define recv_orig ((m->orig))
-#define recv_tiny ((m->tiny))
-
- ao_monitor_tail = ao_monitor_head;
- for (;;) {
- while (ao_monitor_tail == ao_monitor_head)
- ao_sleep(DATA_TO_XDATA(&ao_monitor_head));
- m = &ao_monitor_ring[ao_monitor_tail];
- ao_monitor_tail = ao_monitor_ring_next(ao_monitor_tail);
- switch (ao_monitoring) {
- case AO_MONITORING_ORIG:
- state = recv_orig.telemetry_orig.flight_state;
-
- /* Typical RSSI offset for 38.4kBaud at 433 MHz is 74 */
- rssi = (int16_t) (recv_orig.rssi >> 1) - 74;
- memcpy(callsign, recv_orig.telemetry_orig.callsign, AO_MAX_CALLSIGN);
- if (state > ao_flight_invalid)
- state = ao_flight_invalid;
- if (recv_orig.status & PKT_APPEND_STATUS_1_CRC_OK) {
-
- /* General header fields */
- printf(AO_TELEM_VERSION " %d "
- AO_TELEM_CALL " %s "
- AO_TELEM_SERIAL " %d "
- AO_TELEM_FLIGHT " %d "
- AO_TELEM_RSSI " %d "
- AO_TELEM_STATE " %s "
- AO_TELEM_TICK " %d ",
- AO_TELEMETRY_VERSION,
- callsign,
- recv_orig.telemetry_orig.serial,
- recv_orig.telemetry_orig.flight,
- rssi,
- ao_state_names[state],
- recv_orig.telemetry_orig.adc.tick);
-
- /* Raw sensor values */
- printf(AO_TELEM_RAW_ACCEL " %d "
- AO_TELEM_RAW_BARO " %d "
- AO_TELEM_RAW_THERMO " %d "
- AO_TELEM_RAW_BATT " %d "
- AO_TELEM_RAW_DROGUE " %d "
- AO_TELEM_RAW_MAIN " %d ",
- recv_orig.telemetry_orig.adc.accel,
- recv_orig.telemetry_orig.adc.pres,
- recv_orig.telemetry_orig.adc.temp,
- recv_orig.telemetry_orig.adc.v_batt,
- recv_orig.telemetry_orig.adc.sense_d,
- recv_orig.telemetry_orig.adc.sense_m);
-
- /* Sensor calibration values */
- printf(AO_TELEM_CAL_ACCEL_GROUND " %d "
- AO_TELEM_CAL_BARO_GROUND " %d "
- AO_TELEM_CAL_ACCEL_PLUS " %d "
- AO_TELEM_CAL_ACCEL_MINUS " %d ",
- recv_orig.telemetry_orig.ground_accel,
- recv_orig.telemetry_orig.ground_pres,
- recv_orig.telemetry_orig.accel_plus_g,
- recv_orig.telemetry_orig.accel_minus_g);
-
- if (recv_orig.telemetry_orig.u.k.unused == 0x8000) {
- /* Kalman state values */
- printf(AO_TELEM_KALMAN_HEIGHT " %d "
- AO_TELEM_KALMAN_SPEED " %d "
- AO_TELEM_KALMAN_ACCEL " %d ",
- recv_orig.telemetry_orig.height,
- recv_orig.telemetry_orig.u.k.speed,
- recv_orig.telemetry_orig.accel);
- } else {
- /* Ad-hoc flight values */
- printf(AO_TELEM_ADHOC_ACCEL " %d "
- AO_TELEM_ADHOC_SPEED " %ld "
- AO_TELEM_ADHOC_BARO " %d ",
- recv_orig.telemetry_orig.accel,
- recv_orig.telemetry_orig.u.flight_vel,
- recv_orig.telemetry_orig.height);
- }
- ao_gps_print(&recv_orig.telemetry_orig.gps);
- ao_gps_tracking_print(&recv_orig.telemetry_orig.gps_tracking);
- putchar('\n');
- ao_rssi_set(rssi);
- } else {
- printf("CRC INVALID RSSI %3d\n", rssi);
- }
- break;
- case AO_MONITORING_TINY:
- state = recv_tiny.telemetry_tiny.flight_state;
-
- /* Typical RSSI offset for 38.4kBaud at 433 MHz is 74 */
- rssi = (int16_t) (recv_tiny.rssi >> 1) - 74;
- memcpy(callsign, recv_tiny.telemetry_tiny.callsign, AO_MAX_CALLSIGN);
- if (state > ao_flight_invalid)
- state = ao_flight_invalid;
- if (recv_tiny.status & PKT_APPEND_STATUS_1_CRC_OK) {
- /* General header fields */
- printf(AO_TELEM_VERSION " %d "
- AO_TELEM_CALL " %s "
- AO_TELEM_SERIAL " %d "
- AO_TELEM_FLIGHT " %d "
- AO_TELEM_RSSI " %d "
- AO_TELEM_STATE " %s "
- AO_TELEM_TICK " %d ",
- AO_TELEMETRY_VERSION,
- callsign,
- recv_tiny.telemetry_tiny.serial,
- recv_tiny.telemetry_tiny.flight,
- rssi,
- ao_state_names[state],
- recv_tiny.telemetry_tiny.adc.tick);
-
- /* Raw sensor values */
- printf(AO_TELEM_RAW_BARO " %d "
- AO_TELEM_RAW_THERMO " %d "
- AO_TELEM_RAW_BATT " %d "
- AO_TELEM_RAW_DROGUE " %d "
- AO_TELEM_RAW_MAIN " %d ",
- recv_tiny.telemetry_tiny.adc.pres,
- recv_tiny.telemetry_tiny.adc.temp,
- recv_tiny.telemetry_tiny.adc.v_batt,
- recv_tiny.telemetry_tiny.adc.sense_d,
- recv_tiny.telemetry_tiny.adc.sense_m);
-
- /* Sensor calibration values */
- printf(AO_TELEM_CAL_BARO_GROUND " %d ",
- recv_tiny.telemetry_tiny.ground_pres);
-
-#if 1
- /* Kalman state values */
- printf(AO_TELEM_KALMAN_HEIGHT " %d "
- AO_TELEM_KALMAN_SPEED " %d "
- AO_TELEM_KALMAN_ACCEL " %d\n",
- recv_tiny.telemetry_tiny.height,
- recv_tiny.telemetry_tiny.speed,
- recv_tiny.telemetry_tiny.accel);
-#else
- /* Ad-hoc flight values */
- printf(AO_TELEM_ADHOC_ACCEL " %d "
- AO_TELEM_ADHOC_SPEED " %ld "
- AO_TELEM_ADHOC_BARO " %d\n",
- recv_tiny.telemetry_tiny.flight_accel,
- recv_tiny.telemetry_tiny.flight_vel,
- recv_tiny.telemetry_tiny.flight_pres);
-#endif
- ao_rssi_set(rssi);
- } else {
- printf("CRC INVALID RSSI %3d\n", rssi);
- }
- break;
- default:
- printf ("TELEM %02x", ao_monitoring + 2);
- sum = 0x5a;
- for (state = 0; state < ao_monitoring + 2; state++) {
- byte = recv_raw.packet[state];
- sum += byte;
- printf("%02x", byte);
- }
- printf("%02x\n", sum);
- break;
- }
- ao_usb_flush();
- }
-}
-
-__xdata struct ao_task ao_monitor_get_task;
-__xdata struct ao_task ao_monitor_put_task;
-
-void
-ao_set_monitor(uint8_t monitoring)
-{
- if (ao_monitoring)
- ao_radio_recv_abort();
- ao_monitoring = monitoring;
- ao_wakeup(&ao_monitoring);
-}
-
-static void
-set_monitor(void)
-{
- ao_cmd_hex();
- ao_set_monitor(ao_cmd_lex_i);
-}
-
-__code struct ao_cmds ao_monitor_cmds[] = {
- { set_monitor, "m <0 off, 1 full, 2 tiny>\0Enable/disable radio monitoring" },
- { 0, NULL },
-};
-
-void
-ao_monitor_init(uint8_t monitor_led, uint8_t monitoring) __reentrant
-{
- ao_monitor_led = monitor_led;
- ao_monitoring = monitoring;
- 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");
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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
-ao_mutex_get(__xdata uint8_t *mutex) __reentrant
-{
- if (*mutex == ao_cur_task->task_id)
- ao_panic(AO_PANIC_MUTEX);
- __critical {
- while (*mutex)
- ao_sleep(mutex);
- *mutex = ao_cur_task->task_id;
- }
-}
-
-void
-ao_mutex_put(__xdata uint8_t *mutex) __reentrant
-{
- if (*mutex != ao_cur_task->task_id)
- ao_panic(AO_PANIC_MUTEX);
- __critical {
- *mutex = 0;
- ao_wakeup(mutex);
- }
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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_packet_recv ao_rx_packet;
-__xdata struct ao_packet ao_tx_packet;
-__pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used;
-
-static __xdata char tx_data[AO_PACKET_MAX];
-static __xdata char rx_data[AO_PACKET_MAX];
-static __pdata uint8_t rx_seq;
-
-__xdata struct ao_task ao_packet_task;
-__xdata uint8_t ao_packet_enable;
-__xdata uint8_t ao_packet_master_sleeping;
-
-void
-ao_packet_send(void)
-{
- ao_led_on(AO_LED_RED);
- /* If any tx data is pending then copy it into the tx packet */
- if (ao_packet_tx_used && ao_tx_packet.len == 0) {
- memcpy(&ao_tx_packet.d, tx_data, ao_packet_tx_used);
- ao_tx_packet.len = ao_packet_tx_used;
- ao_tx_packet.seq++;
- ao_packet_tx_used = 0;
- ao_wakeup(&tx_data);
- }
- ao_radio_send(&ao_tx_packet, sizeof (ao_tx_packet));
- ao_led_off(AO_LED_RED);
-}
-
-uint8_t
-ao_packet_recv(void)
-{
- uint8_t dma_done;
-
-#ifdef AO_LED_GREEN
- ao_led_on(AO_LED_GREEN);
-#endif
- dma_done = ao_radio_recv(&ao_rx_packet, sizeof (struct ao_packet_recv));
-#ifdef AO_LED_GREEN
- ao_led_off(AO_LED_GREEN);
-#endif
-
- /* Check to see if we got a valid packet */
- if (!dma_done)
- return 0;
- if (!(ao_rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK))
- return 0;
-
- /* SYN packets carry no data */
- if (ao_rx_packet.packet.len == AO_PACKET_SYN) {
- rx_seq = ao_rx_packet.packet.seq;
- ao_tx_packet.seq = ao_rx_packet.packet.ack;
- ao_tx_packet.ack = rx_seq;
- } else if (ao_rx_packet.packet.len) {
-
- /* Check for incoming data at the next sequence and
- * for an empty data buffer
- */
- if (ao_rx_packet.packet.seq == (uint8_t) (rx_seq + (uint8_t) 1) &&
- ao_packet_rx_used == ao_packet_rx_len) {
-
- /* Copy data to the receive data buffer and set up the
- * offsets
- */
- memcpy(rx_data, ao_rx_packet.packet.d, ao_rx_packet.packet.len);
- ao_packet_rx_used = 0;
- ao_packet_rx_len = ao_rx_packet.packet.len;
-
- /* Mark the sequence that we've received to
- * let the sender know when we return a packet
- */
- rx_seq = ao_rx_packet.packet.seq;
- ao_tx_packet.ack = rx_seq;
-
- /* Poke anyone looking for received data */
- ao_wakeup(&ao_stdin_ready);
- }
- }
-
- /* If the other side has seen the latest data we queued,
- * wake up any task waiting to send data and let them go again
- */
- if (ao_rx_packet.packet.ack == ao_tx_packet.seq) {
- ao_tx_packet.len = 0;
- ao_wakeup(&ao_tx_packet);
- }
- return 1;
-}
-
-#ifndef PACKET_HAS_MASTER
-#define PACKET_HAS_MASTER 1
-#endif
-
-#if PACKET_HAS_MASTER
-void
-ao_packet_flush(void)
-{
- /* If there is data to send, and this is the master,
- * then poke the master to send all queued data
- */
- if (ao_packet_tx_used && ao_packet_master_sleeping)
- ao_wakeup(&ao_packet_master_sleeping);
-}
-#endif /* PACKET_HAS_MASTER */
-
-void
-ao_packet_putchar(char c) __reentrant
-{
- while (ao_packet_tx_used == AO_PACKET_MAX && ao_packet_enable) {
-#if PACKET_HAS_MASTER
- ao_packet_flush();
-#endif
- ao_sleep(&tx_data);
- }
-
- if (ao_packet_enable)
- tx_data[ao_packet_tx_used++] = c;
-}
-
-char
-ao_packet_pollchar(void) __critical
-{
- if (!ao_packet_enable)
- return AO_READ_AGAIN;
-
- if (ao_packet_rx_used == ao_packet_rx_len)
- return AO_READ_AGAIN;
-
- return rx_data[ao_packet_rx_used++];
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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 char
-ao_packet_getchar(void) __critical
-{
- char c;
- while ((c = ao_packet_pollchar()) == AO_READ_AGAIN) {
- if (!ao_packet_enable)
- break;
- if (ao_packet_master_sleeping)
- ao_wakeup(&ao_packet_master_sleeping);
- flush();
- ao_sleep(&ao_stdin_ready);
- }
- return c;
-}
-
-static void
-ao_packet_echo(void) __reentrant
-{
- char c;
- while (ao_packet_enable) {
- c = ao_packet_getchar();
- if (c != AO_READ_AGAIN)
- putchar(c);
- }
- ao_exit();
-}
-
-static __xdata struct ao_task ao_packet_echo_task;
-static __xdata uint16_t ao_packet_master_delay;
-static __xdata uint16_t ao_packet_master_time;
-
-#define AO_PACKET_MASTER_DELAY_SHORT AO_MS_TO_TICKS(100)
-#define AO_PACKET_MASTER_DELAY_LONG AO_MS_TO_TICKS(1000)
-#define AO_PACKET_MASTER_DELAY_TIMEOUT AO_MS_TO_TICKS(2000)
-
-static void
-ao_packet_master_busy(void)
-{
- ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT;
- ao_packet_master_time = ao_time();
-}
-
-static void
-ao_packet_master_check_busy(void)
-{
- int16_t idle;
- if (ao_packet_master_delay != AO_PACKET_MASTER_DELAY_SHORT)
- return;
- idle = (int16_t) (ao_time() - ao_packet_master_time);
-
- if (idle > AO_PACKET_MASTER_DELAY_TIMEOUT)
- ao_packet_master_delay = AO_PACKET_MASTER_DELAY_LONG;
-}
-
-void
-ao_packet_master(void)
-{
- ao_config_get();
- ao_tx_packet.addr = ao_serial_number;
- ao_tx_packet.len = AO_PACKET_SYN;
- ao_packet_master_time = ao_time();
- ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT;
- while (ao_packet_enable) {
- 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()) {
- /* if we can transmit data, do so */
- if (ao_packet_tx_used && ao_tx_packet.len == 0)
- continue;
- if (ao_rx_packet.packet.len)
- ao_packet_master_busy();
- ao_packet_master_sleeping = 1;
- ao_alarm(ao_packet_master_delay);
- ao_sleep(&ao_packet_master_sleeping);
- ao_packet_master_sleeping = 0;
- }
- }
- ao_exit();
-}
-
-static void
-ao_packet_forward(void) __reentrant
-{
- char c;
- ao_packet_enable = 1;
- ao_cmd_white();
-
- flush();
-#if HAS_MONITOR
- ao_set_monitor(0);
-#endif
- ao_add_task(&ao_packet_task, ao_packet_master, "master");
- ao_add_task(&ao_packet_echo_task, ao_packet_echo, "echo");
- while ((c = getchar()) != '~') {
- if (c == '\r') c = '\n';
- ao_packet_putchar(c);
- }
-
- /* Wait for a second if there is any pending data */
- for (c = 0; (ao_packet_tx_used || ao_tx_packet.len) && c < 10; c++)
- ao_delay(AO_MS_TO_TICKS(100));
- ao_packet_enable = 0;
- while (ao_packet_echo_task.wchan || ao_packet_task.wchan) {
- ao_radio_recv_abort();
- ao_wakeup(&ao_stdin_ready);
- ao_delay(AO_MS_TO_TICKS(10));
- }
-}
-
-
-
-__code struct ao_cmds ao_packet_master_cmds[] = {
- { ao_packet_forward, "p\0Remote packet link." },
- { 0, NULL },
-};
-
-void
-ao_packet_master_init(void)
-{
- ao_cmd_register(&ao_packet_master_cmds[0]);
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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
-ao_packet_slave(void)
-{
- ao_tx_packet.addr = ao_serial_number;
- ao_tx_packet.len = AO_PACKET_SYN;
- while (ao_packet_enable) {
- if (ao_packet_recv()) {
- memcpy(&ao_tx_packet.callsign, &ao_rx_packet.packet.callsign, AO_MAX_CALLSIGN);
-#if HAS_FLIGHT
- ao_flight_force_idle = TRUE;
-#endif
- ao_packet_send();
- }
- }
- ao_exit();
-}
-
-void
-ao_packet_slave_start(void)
-{
- if (!ao_packet_enable) {
- ao_packet_enable = 1;
- ao_add_task(&ao_packet_task, ao_packet_slave, "slave");
- }
-}
-
-void
-ao_packet_slave_stop(void)
-{
- if (ao_packet_enable) {
- ao_packet_enable = 0;
- while (ao_packet_task.wchan) {
- ao_radio_recv_abort();
- ao_delay(AO_MS_TO_TICKS(10));
- }
- }
-}
-
-void
-ao_packet_slave_init(uint8_t enable)
-{
- ao_add_stdio(ao_packet_pollchar,
- ao_packet_putchar,
- NULL);
- if (enable)
- ao_packet_slave_start();
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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"
-
-#ifndef HAS_BEEP
-#error Please define HAS_BEEP
-#endif
-
-#if !HAS_BEEP
-#define ao_beep(x)
-#endif
-
-static void
-ao_panic_delay(uint8_t n)
-{
- uint8_t i = 0, j = 0;
-
- while (n--)
- while (--j)
- while (--i)
- _asm nop _endasm;
-}
-
-void
-ao_panic(uint8_t reason)
-{
- uint8_t n;
-
- __critical for (;;) {
- ao_panic_delay(20);
- for (n = 0; n < 5; n++) {
- ao_led_on(AO_LED_RED);
- ao_beep(AO_BEEP_HIGH);
- ao_panic_delay(1);
- ao_led_off(AO_LED_RED);
- ao_beep(AO_BEEP_LOW);
- ao_panic_delay(1);
- }
- ao_beep(AO_BEEP_OFF);
- ao_panic_delay(2);
-#pragma disable_warning 126
- for (n = 0; n < reason; n++) {
- ao_led_on(AO_LED_RED);
- ao_beep(AO_BEEP_MID);
- ao_panic_delay(10);
- ao_led_off(AO_LED_RED);
- ao_beep(AO_BEEP_OFF);
- ao_panic_delay(10);
- }
- }
-}
+++ /dev/null
-/*
- * 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.
- */
-
-#ifndef _AO_PINS_H_
-#define _AO_PINS_H_
-
-#if defined(TELEMETRUM_V_1_0)
- #define HAS_FLIGHT 1
- #define HAS_USB 1
- #define HAS_BEEP 1
- #define HAS_GPS 1
- #define HAS_SERIAL_1 1
- #define HAS_ADC 1
- #define USE_SERIAL_STDIN 0
- #define HAS_EEPROM 1
- #define USE_INTERNAL_FLASH 0
- #define HAS_DBG 1
- #define DBG_ON_P1 1
- #define DBG_ON_P0 0
- #define IGNITE_ON_P2 1
- #define IGNITE_ON_P0 0
- #define PACKET_HAS_MASTER 0
- #define PACKET_HAS_SLAVE 1
-
- #define HAS_COMPANION 1
- #define COMPANION_CS_ON_P1 1
- #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */
- #define COMPANION_CS P1_2
-
- #define AO_LED_RED 1
- #define LEDS_AVAILABLE (AO_LED_RED)
- #define HAS_EXTERNAL_TEMP 0
- #define HAS_ACCEL_REF 0
- #define HAS_ACCEL 1
- #define HAS_IGNITE 1
- #define HAS_MONITOR 0
-#endif
-
-#if defined(TELEMETRUM_V_1_1)
- #define HAS_FLIGHT 1
- #define HAS_USB 1
- #define HAS_BEEP 1
- #define HAS_GPS 1
- #define HAS_SERIAL_1 1
- #define USE_SERIAL_STDIN 0
- #define HAS_ADC 1
- #define HAS_EEPROM 1
- #define USE_INTERNAL_FLASH 0
- #define HAS_DBG 1
- #define DBG_ON_P1 1
- #define DBG_ON_P0 0
- #define IGNITE_ON_P2 1
- #define IGNITE_ON_P0 0
- #define PACKET_HAS_MASTER 0
- #define PACKET_HAS_SLAVE 1
-
- #define HAS_COMPANION 1
- #define COMPANION_CS_ON_P1 1
- #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */
- #define COMPANION_CS P1_2
-
- #define AO_LED_RED 1
- #define LEDS_AVAILABLE (AO_LED_RED)
- #define HAS_EXTERNAL_TEMP 0
- #define HAS_ACCEL_REF 1
- #define SPI_CS_ON_P1 1
- #define SPI_CS_ON_P0 0
- #define M25_CS_MASK 0x02 /* CS0 is P1_1 */
- #define M25_MAX_CHIPS 1
- #define HAS_ACCEL 1
- #define HAS_IGNITE 1
- #define HAS_MONITOR 0
-#endif
-
-#if defined(TELEDONGLE_V_0_2)
- #define HAS_FLIGHT 0
- #define HAS_USB 1
- #define HAS_BEEP 0
- #define HAS_SERIAL_1 0
- #define USE_SERIAL_STDIN 0
- #define HAS_ADC 0
- #define HAS_DBG 1
- #define HAS_EEPROM 0
- #define DBG_ON_P1 1
- #define DBG_ON_P0 0
- #define IGNITE_ON_P2 0
- #define IGNITE_ON_P0 0
- #define PACKET_HAS_MASTER 1
- #define PACKET_HAS_SLAVE 0
- #define AO_LED_RED 1
- #define AO_LED_GREEN 2
- #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN)
- #define SPI_CS_ON_P1 1
- #define SPI_CS_ON_P0 0
- #define HAS_IGNITE 0
- #define HAS_MONITOR 1
-#endif
-
-#if defined(TELEMINI_V_1_0)
- #define HAS_FLIGHT 1
- #define HAS_USB 0
- #define HAS_BEEP 0
- #define HAS_GPS 0
- #define HAS_SERIAL_1 0
- #define USE_SERIAL_STDIN 0
- #define HAS_ADC 1
- #define HAS_EEPROM 1
- #define USE_INTERNAL_FLASH 1
- #define HAS_DBG 0
- #define IGNITE_ON_P2 0
- #define IGNITE_ON_P0 1
- #define PACKET_HAS_MASTER 0
- #define PACKET_HAS_SLAVE 1
- #define USE_FAST_ASCENT_LOG 1
-
- #define AO_LED_GREEN 1
- #define AO_LED_RED 2
- #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN)
- #define HAS_EXTERNAL_TEMP 0
- #define HAS_ACCEL 0
- #define HAS_IGNITE 1
- #define HAS_MONITOR 0
-#endif
-
-#if defined(TELENANO_V_0_1)
- #define HAS_FLIGHT 1
- #define HAS_USB 0
- #define HAS_BEEP 0
- #define HAS_GPS 0
- #define HAS_SERIAL_1 0
- #define USE_SERIAL_STDIN 0
- #define HAS_ADC 1
- #define HAS_EEPROM 1
- #define USE_INTERNAL_FLASH 1
- #define HAS_DBG 0
- #define IGNITE_ON_P2 0
- #define IGNITE_ON_P0 1
- #define PACKET_HAS_MASTER 0
- #define PACKET_HAS_SLAVE 1
-
- #define AO_LED_GREEN 1
- #define AO_LED_RED 2
- #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN)
- #define HAS_EXTERNAL_TEMP 0
- #define HAS_ACCEL 0
- #define HAS_IGNITE 0
- #define HAS_MONITOR 0
-#endif
-
-#if defined(TELEMETRUM_V_0_1)
- #define HAS_FLIGHT 1
- #define HAS_USB 1
- #define HAS_BEEP 1
- #define HAS_GPS 1
- #define HAS_SERIAL_1 1
- #define USE_SERIAL_STDIN 0
- #define HAS_ADC 1
- #define HAS_DBG 0
- #define HAS_EEPROM 1
- #define USE_INTERNAL_FLASH 0
- #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 1
- #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 1
- #define HAS_IGNITE 1
- #define HAS_MONITOR 0
-#endif
-
-#if defined(TELEDONGLE_V_0_1)
- #define HAS_FLIGHT 0
- #define HAS_USB 1
- #define HAS_BEEP 0
- #define HAS_SERIAL_1 0
- #define USE_SERIAL_STDIN 0
- #define HAS_ADC 0
- #define HAS_DBG 0
- #define HAS_EEPROM 0
- #define DBG_ON_P1 0
- #define DBG_ON_P0 1
- #define IGNITE_ON_P2 0
- #define IGNITE_ON_P0 0
- #define PACKET_HAS_MASTER 1
- #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 SPI_CS_ON_P1 0
- #define SPI_CS_ON_P0 1
- #define HAS_IGNITE 0
- #define HAS_MONITOR 1
-#endif
-
-#if defined(TIDONGLE)
- #define HAS_FLIGHT 0
- #define HAS_USB 1
- #define HAS_BEEP 0
- #define HAS_SERIAL_1 0
- #define USE_SERIAL_STDIN 0
- #define HAS_ADC 0
- #define HAS_DBG 1
- #define HAS_EEPROM 0
- #define DBG_ON_P1 0
- #define DBG_ON_P0 1
- #define IGNITE_ON_P2 0
- #define IGNITE_ON_P0 0
- #define PACKET_HAS_MASTER 1
- #define PACKET_HAS_SLAVE 0
- #define AO_LED_RED 2
- #define LEDS_AVAILABLE (AO_LED_RED)
- #define SPI_CS_ON_P1 0
- #define SPI_CS_ON_P0 1
- #define HAS_IGNITE 0
- #define HAS_MONITOR 1
-#endif
-
-#if defined(TELEBT_V_0_0)
- #define HAS_FLIGHT 0
- #define HAS_USB 1
- #define HAS_BEEP 0
- #define HAS_SERIAL_1 1
- #define USE_SERIAL_STDIN 1
- #define HAS_ADC 0
- #define HAS_DBG 1
- #define HAS_EEPROM 0
- #define HAS_BTM 1
- #define DBG_ON_P1 0
- #define DBG_ON_P0 1
- #define IGNITE_ON_P2 0
- #define IGNITE_ON_P0 0
- #define PACKET_HAS_MASTER 1
- #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 SPI_CS_ON_P1 1
- #define SPI_CS_ON_P0 0
- #define HAS_IGNITE 0
- #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
-#endif
-
-#if defined(TELEBT_V_0_1)
- #define HAS_FLIGHT 0
- #define HAS_USB 1
- #define HAS_BEEP 1
- #define HAS_SERIAL_1 1
- #define HAS_SERIAL_1_ALT_1 1
- #define HAS_SERIAL_1_ALT_2 0
- #define HAS_SERIAL_1_HW_FLOW 1
- #define USE_SERIAL_STDIN 1
- #define HAS_ADC 0
- #define HAS_DBG 1
- #define HAS_EEPROM 1
- #define USE_INTERNAL_FLASH 0
- #define HAS_BTM 1
- #define DBG_ON_P1 1
- #define DBG_ON_P0 0
- #define IGNITE_ON_P2 0
- #define IGNITE_ON_P0 0
- #define PACKET_HAS_MASTER 1
- #define PACKET_HAS_SLAVE 0
- #define AO_LED_RED 1
- #define AO_LED_GREEN 2
- #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN)
- #define SPI_CS_ON_P1 1
- #define SPI_CS_ON_P0 0
- #define M25_CS_MASK 0x04 /* CS0 is P1_2 */
- #define M25_MAX_CHIPS 1
- #define HAS_ACCEL 0
- #define HAS_IGNITE 0
- #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
-#endif
-
-#if DBG_ON_P1
-
- #define DBG_CLOCK (1 << 4) /* mi0 */
- #define DBG_DATA (1 << 5) /* mo0 */
- #define DBG_RESET_N (1 << 3) /* c0 */
-
- #define DBG_CLOCK_PIN (P1_4)
- #define DBG_DATA_PIN (P1_5)
- #define DBG_RESET_N_PIN (P1_3)
-
- #define DBG_PORT_NUM 1
- #define DBG_PORT P1
- #define DBG_PORT_SEL P1SEL
- #define DBG_PORT_INP P1INP
- #define DBG_PORT_DIR P1DIR
-
-#endif /* DBG_ON_P1 */
-
-#if DBG_ON_P0
-
- #define DBG_CLOCK (1 << 3)
- #define DBG_DATA (1 << 4)
- #define DBG_RESET_N (1 << 5)
-
- #define DBG_CLOCK_PIN (P0_3)
- #define DBG_DATA_PIN (P0_4)
- #define DBG_RESET_N_PIN (P0_5)
-
- #define DBG_PORT_NUM 0
- #define DBG_PORT P0
- #define DBG_PORT_SEL P0SEL
- #define DBG_PORT_INP P0INP
- #define DBG_PORT_DIR P0DIR
-
-#endif /* DBG_ON_P0 */
-
-#if COMPANION_CS_ON_P1
- #define COMPANION_CS_PORT P1
- #define COMPANION_CS_SEL P1SEL
- #define COMPANION_CS_DIR P1DIR
-#endif
-
-#if SPI_CS_ON_P1
- #define SPI_CS_PORT P1
- #define SPI_CS_SEL P1SEL
- #define SPI_CS_DIR P1DIR
-#endif
-
-#if SPI_CS_ON_P0
- #define SPI_CS_PORT P0
- #define SPI_CS_SEL P0SEL
- #define SPI_CS_DIR P0DIR
-#endif
-
-#ifndef IGNITE_ON_P2
-#error Please define IGNITE_ON_P2
-#endif
-
-#ifndef IGNITE_ON_P0
-#error Please define IGNITE_ON_P0
-#endif
-
-#ifndef HAS_SERIAL_1
-#error Please define HAS_SERIAL_1
-#endif
-
-#ifndef USE_SERIAL_STDIN
-#error Please define USE_SERIAL_STDIN
-#endif
-
-#ifndef HAS_ADC
-#error Please define HAS_ADC
-#endif
-
-#ifndef HAS_EEPROM
-#error Please define HAS_EEPROM
-#endif
-
-#if HAS_EEPROM
-#ifndef USE_INTERNAL_FLASH
-#error Please define USE_INTERNAL_FLASH
-#endif
-#endif
-
-#ifndef HAS_DBG
-#error Please define HAS_DBG
-#endif
-
-#ifndef HAS_IGNITE
-#error Please define HAS_IGNITE
-#endif
-
-#ifndef PACKET_HAS_MASTER
-#error Please define PACKET_HAS_MASTER
-#endif
-
-#ifndef PACKET_HAS_SLAVE
-#error Please define PACKET_HAS_SLAVE
-#endif
-
-#ifndef HAS_MONITOR
-#error Please define HAS_MONITOR
-#endif
-#endif /* _AO_PINS_H_ */
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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"
-
-/* Defines which mark this particular AltOS product */
-
-const char ao_version[AO_MAX_VERSION] = AO_iVersion_STRING;
-const char ao_manufacturer[] = AO_iManufacturer_STRING;
-const char ao_product[] = AO_iProduct_STRING;
-
-#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8))
-
-#if HAS_USB
-#include "ao_usb.h"
-/* USB descriptors in one giant block of bytes */
-__code __at(0x00aa) uint8_t ao_usb_descriptors [] =
-{
- /* Device descriptor */
- 0x12,
- AO_USB_DESC_DEVICE,
- LE_WORD(0x0110), /* bcdUSB */
- 0x02, /* bDeviceClass */
- 0x00, /* bDeviceSubClass */
- 0x00, /* bDeviceProtocol */
- AO_USB_CONTROL_SIZE, /* bMaxPacketSize */
- LE_WORD(0xFFFE), /* idVendor */
- LE_WORD(AO_idProduct_NUMBER), /* idProduct */
- LE_WORD(0x0100), /* bcdDevice */
- 0x01, /* iManufacturer */
- 0x02, /* iProduct */
- 0x03, /* iSerialNumber */
- 0x01, /* bNumConfigurations */
-
- /* Configuration descriptor */
- 0x09,
- AO_USB_DESC_CONFIGURATION,
- LE_WORD(67), /* wTotalLength */
- 0x02, /* bNumInterfaces */
- 0x01, /* bConfigurationValue */
- 0x00, /* iConfiguration */
- 0xC0, /* bmAttributes */
- 0x32, /* bMaxPower */
-
- /* Control class interface */
- 0x09,
- AO_USB_DESC_INTERFACE,
- 0x00, /* bInterfaceNumber */
- 0x00, /* bAlternateSetting */
- 0x01, /* bNumEndPoints */
- 0x02, /* bInterfaceClass */
- 0x02, /* bInterfaceSubClass */
- 0x01, /* bInterfaceProtocol, linux requires value of 1 for the cdc_acm module */
- 0x00, /* iInterface */
-
- /* Header functional descriptor */
- 0x05,
- CS_INTERFACE,
- 0x00, /* bDescriptor SubType Header */
- LE_WORD(0x0110), /* CDC version 1.1 */
-
- /* Call management functional descriptor */
- 0x05,
- CS_INTERFACE,
- 0x01, /* bDescriptor SubType Call Management */
- 0x01, /* bmCapabilities = device handles call management */
- 0x01, /* bDataInterface call management interface number */
-
- /* ACM functional descriptor */
- 0x04,
- CS_INTERFACE,
- 0x02, /* bDescriptor SubType Abstract Control Management */
- 0x02, /* bmCapabilities = D1 (Set_line_Coding, Set_Control_Line_State, Get_Line_Coding and Serial_State) */
-
- /* Union functional descriptor */
- 0x05,
- CS_INTERFACE,
- 0x06, /* bDescriptor SubType Union Functional descriptor */
- 0x00, /* bMasterInterface */
- 0x01, /* bSlaveInterface0 */
-
- /* Notification EP */
- 0x07,
- AO_USB_DESC_ENDPOINT,
- AO_USB_INT_EP|0x80, /* bEndpointAddress */
- 0x03, /* bmAttributes = intr */
- LE_WORD(8), /* wMaxPacketSize */
- 0x0A, /* bInterval */
-
- /* Data class interface descriptor */
- 0x09,
- AO_USB_DESC_INTERFACE,
- 0x01, /* bInterfaceNumber */
- 0x00, /* bAlternateSetting */
- 0x02, /* bNumEndPoints */
- 0x0A, /* bInterfaceClass = data */
- 0x00, /* bInterfaceSubClass */
- 0x00, /* bInterfaceProtocol */
- 0x00, /* iInterface */
-
- /* Data EP OUT */
- 0x07,
- AO_USB_DESC_ENDPOINT,
- AO_USB_OUT_EP, /* bEndpointAddress */
- 0x02, /* bmAttributes = bulk */
- LE_WORD(AO_USB_OUT_SIZE),/* wMaxPacketSize */
- 0x00, /* bInterval */
-
- /* Data EP in */
- 0x07,
- AO_USB_DESC_ENDPOINT,
- AO_USB_IN_EP|0x80, /* bEndpointAddress */
- 0x02, /* bmAttributes = bulk */
- LE_WORD(AO_USB_IN_SIZE),/* wMaxPacketSize */
- 0x00, /* bInterval */
-
- /* String descriptors */
- 0x04,
- AO_USB_DESC_STRING,
- LE_WORD(0x0409),
-
- /* iManufacturer */
- AO_iManufacturer_LEN,
- AO_USB_DESC_STRING,
- AO_iManufacturer_UCS2,
-
- /* iProduct */
- AO_iProduct_LEN,
- AO_USB_DESC_STRING,
- AO_iProduct_UCS2,
-
- /* iSerial */
- AO_iSerial_LEN,
- AO_USB_DESC_STRING,
- AO_iSerial_UCS2,
-
- /* Terminating zero */
- 0
-};
-#endif
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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"
-
-/* Values from SmartRF® Studio for:
- *
- * Deviation: 20.507812 kHz
- * Datarate: 38.360596 kBaud
- * Modulation: GFSK
- * RF Freq: 434.549927 MHz
- * Channel: 99.975586 kHz
- * Channel: 0
- * RX filter: 93.75 kHz
- */
-
-/*
- * For IF freq of 140.62kHz, the IF value is:
- *
- * 140.62e3 / (24e6 / 2**10) = 6
- */
-
-#define IF_FREQ_CONTROL 6
-
-/*
- * For channel bandwidth of 93.75 kHz, the CHANBW_E and CHANBW_M values are
- *
- * BW = 24e6 / (8 * (4 + M) * 2 ** E)
- *
- * So, M = 0 and E = 3
- */
-
-#define CHANBW_M 0
-#define CHANBW_E 3
-
-/*
- * For a symbol rate of 38360kBaud, the DRATE_E and DRATE_M values are:
- *
- * R = (256 + M) * 2** E * 24e6 / 2**28
- *
- * So M is 163 and E is 10
- */
-
-#define DRATE_E 10
-#define DRATE_M 163
-
-/*
- * For a channel deviation of 20.5kHz, the DEVIATION_E and DEVIATION_M values are:
- *
- * F = 24e6/2**17 * (8 + DEVIATION_M) * 2**DEVIATION_E
- *
- * So M is 6 and E is 3
- */
-
-#define DEVIATION_M 6
-#define DEVIATION_E 3
-
-/*
- * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone),
- * so the DRATE_E and DRATE_M values are:
- *
- * M is 94 and E is 6
- *
- * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes
- */
-
-#define RDF_DRATE_E 6
-#define RDF_DRATE_M 94
-#define RDF_PACKET_LEN 50
-
-/*
- * RDF deviation should match the normal NFM value of 5kHz
- *
- * M is 6 and E is 1
- *
- */
-
-#define RDF_DEVIATION_M 6
-#define RDF_DEVIATION_E 1
-
-/* This are from the table for 433MHz */
-
-#define RF_POWER_M30_DBM 0x12
-#define RF_POWER_M20_DBM 0x0e
-#define RF_POWER_M15_DBM 0x1d
-#define RF_POWER_M10_DBM 0x34
-#define RF_POWER_M5_DBM 0x2c
-#define RF_POWER_0_DBM 0x60
-#define RF_POWER_5_DBM 0x84
-#define RF_POWER_7_DBM 0xc8
-#define RF_POWER_10_DBM 0xc0
-
-#define RF_POWER RF_POWER_10_DBM
-
-static __code uint8_t radio_setup[] = {
- RF_PA_TABLE7_OFF, RF_POWER,
- RF_PA_TABLE6_OFF, RF_POWER,
- RF_PA_TABLE5_OFF, RF_POWER,
- RF_PA_TABLE4_OFF, RF_POWER,
- RF_PA_TABLE3_OFF, RF_POWER,
- RF_PA_TABLE2_OFF, RF_POWER,
- RF_PA_TABLE1_OFF, RF_POWER,
- RF_PA_TABLE0_OFF, RF_POWER,
-
- RF_FSCTRL1_OFF, (IF_FREQ_CONTROL << RF_FSCTRL1_FREQ_IF_SHIFT),
- RF_FSCTRL0_OFF, (0 << RF_FSCTRL0_FREQOFF_SHIFT),
-
- RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
- (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) |
- (DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)),
- RF_MDMCFG3_OFF, (DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT),
- RF_MDMCFG2_OFF, (RF_MDMCFG2_DEM_DCFILT_OFF |
- RF_MDMCFG2_MOD_FORMAT_GFSK |
- RF_MDMCFG2_SYNC_MODE_15_16_THRES),
- RF_MDMCFG1_OFF, (RF_MDMCFG1_FEC_EN |
- RF_MDMCFG1_NUM_PREAMBLE_4 |
- (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)),
- RF_MDMCFG0_OFF, (17 << RF_MDMCFG0_CHANSPC_M_SHIFT),
-
- RF_CHANNR_OFF, 0,
-
- RF_DEVIATN_OFF, ((DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) |
- (DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)),
-
- /* SmartRF says set LODIV_BUF_CURRENT_TX to 0
- * And, we're not using power ramping, so use PA_POWER 0
- */
- RF_FREND0_OFF, ((1 << RF_FREND0_LODIV_BUF_CURRENT_TX_SHIFT) |
- (0 << RF_FREND0_PA_POWER_SHIFT)),
-
- RF_FREND1_OFF, ((1 << RF_FREND1_LNA_CURRENT_SHIFT) |
- (1 << RF_FREND1_LNA2MIX_CURRENT_SHIFT) |
- (1 << RF_FREND1_LODIV_BUF_CURRENT_RX_SHIFT) |
- (2 << RF_FREND1_MIX_CURRENT_SHIFT)),
-
- RF_FSCAL3_OFF, 0xE9,
- RF_FSCAL2_OFF, 0x0A,
- RF_FSCAL1_OFF, 0x00,
- RF_FSCAL0_OFF, 0x1F,
-
- RF_TEST2_OFF, 0x88,
- RF_TEST1_OFF, 0x31,
- RF_TEST0_OFF, 0x09,
-
- /* default sync values */
- RF_SYNC1_OFF, 0xD3,
- RF_SYNC0_OFF, 0x91,
-
- /* max packet length */
- RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)|
- PKTCTRL1_APPEND_STATUS|
- PKTCTRL1_ADR_CHK_NONE),
- RF_PKTCTRL0_OFF, (RF_PKTCTRL0_WHITE_DATA|
- RF_PKTCTRL0_PKT_FORMAT_NORMAL|
- RF_PKTCTRL0_CRC_EN|
- RF_PKTCTRL0_LENGTH_CONFIG_FIXED),
- RF_ADDR_OFF, 0x00,
- RF_MCSM2_OFF, (RF_MCSM2_RX_TIME_END_OF_PACKET),
- RF_MCSM1_OFF, (RF_MCSM1_CCA_MODE_RSSI_BELOW_UNLESS_RECEIVING|
- RF_MCSM1_RXOFF_MODE_IDLE|
- RF_MCSM1_TXOFF_MODE_IDLE),
- RF_MCSM0_OFF, (RF_MCSM0_FS_AUTOCAL_FROM_IDLE|
- RF_MCSM0_MAGIC_3|
- RF_MCSM0_CLOSE_IN_RX_0DB),
- RF_FOCCFG_OFF, (RF_FOCCFG_FOC_PRE_K_3K,
- RF_FOCCFG_FOC_POST_K_PRE_K,
- RF_FOCCFG_FOC_LIMIT_BW_OVER_4),
- RF_BSCFG_OFF, (RF_BSCFG_BS_PRE_K_2K|
- RF_BSCFG_BS_PRE_KP_3KP|
- RF_BSCFG_BS_POST_KI_PRE_KI|
- RF_BSCFG_BS_POST_KP_PRE_KP|
- RF_BSCFG_BS_LIMIT_0),
- RF_AGCCTRL2_OFF, 0x43,
- RF_AGCCTRL1_OFF, 0x40,
- RF_AGCCTRL0_OFF, 0x91,
-
- RF_IOCFG2_OFF, 0x00,
- RF_IOCFG1_OFF, 0x00,
- RF_IOCFG0_OFF, 0x00,
-};
-
-static __code uint8_t rdf_setup[] = {
- RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
- (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) |
- (RDF_DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)),
- RF_MDMCFG3_OFF, (RDF_DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT),
- RF_MDMCFG2_OFF, (RF_MDMCFG2_DEM_DCFILT_OFF |
- RF_MDMCFG2_MOD_FORMAT_GFSK |
- RF_MDMCFG2_SYNC_MODE_15_16_THRES),
- RF_MDMCFG1_OFF, (RF_MDMCFG1_FEC_DIS |
- RF_MDMCFG1_NUM_PREAMBLE_2 |
- (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)),
-
- RF_DEVIATN_OFF, ((RDF_DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) |
- (RDF_DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)),
-
- /* packet length is set in-line */
- RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)|
- PKTCTRL1_ADR_CHK_NONE),
- RF_PKTCTRL0_OFF, (RF_PKTCTRL0_PKT_FORMAT_NORMAL|
- RF_PKTCTRL0_LENGTH_CONFIG_FIXED),
-};
-
-static __code uint8_t fixed_pkt_setup[] = {
- RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
- (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) |
- (DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)),
- RF_MDMCFG3_OFF, (DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT),
- RF_MDMCFG2_OFF, (RF_MDMCFG2_DEM_DCFILT_OFF |
- RF_MDMCFG2_MOD_FORMAT_GFSK |
- RF_MDMCFG2_SYNC_MODE_15_16_THRES),
- RF_MDMCFG1_OFF, (RF_MDMCFG1_FEC_EN |
- RF_MDMCFG1_NUM_PREAMBLE_4 |
- (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)),
-
- RF_DEVIATN_OFF, ((DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) |
- (DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)),
-
- /* max packet length -- now set inline */
- RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)|
- PKTCTRL1_APPEND_STATUS|
- PKTCTRL1_ADR_CHK_NONE),
- RF_PKTCTRL0_OFF, (RF_PKTCTRL0_WHITE_DATA|
- RF_PKTCTRL0_PKT_FORMAT_NORMAL|
- RF_PKTCTRL0_CRC_EN|
- RF_PKTCTRL0_LENGTH_CONFIG_FIXED),
-};
-
-__xdata uint8_t ao_radio_dma;
-__xdata uint8_t ao_radio_dma_done;
-__xdata uint8_t ao_radio_done;
-__xdata uint8_t ao_radio_abort;
-__xdata uint8_t ao_radio_mutex;
-
-void
-ao_radio_general_isr(void) __interrupt 16
-{
- S1CON &= ~0x03;
- if (RFIF & RFIF_IM_TIMEOUT) {
- ao_radio_recv_abort();
- RFIF &= ~ RFIF_IM_TIMEOUT;
- } else if (RFIF & RFIF_IM_DONE) {
- ao_radio_done = 1;
- ao_wakeup(&ao_radio_done);
- RFIF &= ~RFIF_IM_DONE;
- }
-}
-
-void
-ao_radio_set_packet(void)
-{
- uint8_t i;
- for (i = 0; i < sizeof (fixed_pkt_setup); i += 2)
- RF[fixed_pkt_setup[i]] = fixed_pkt_setup[i+1];
-}
-
-void
-ao_radio_idle(void)
-{
- if (RF_MARCSTATE != RF_MARCSTATE_IDLE)
- {
- do {
- RFST = RFST_SIDLE;
- ao_yield();
- } while (RF_MARCSTATE != RF_MARCSTATE_IDLE);
- }
-}
-
-void
-ao_radio_get(uint8_t len)
-{
- ao_config_get();
- ao_mutex_get(&ao_radio_mutex);
- ao_radio_idle();
- RF_CHANNR = ao_config.radio_channel;
- RF_FREQ2 = (uint8_t) (ao_config.radio_setting >> 16);
- RF_FREQ1 = (uint8_t) (ao_config.radio_setting >> 8);
- RF_FREQ0 = (uint8_t) (ao_config.radio_setting);
- RF_PKTLEN = len;
-}
-
-
-void
-ao_radio_send(__xdata void *packet, uint8_t size) __reentrant
-{
- ao_radio_get(size);
- ao_radio_done = 0;
- ao_dma_set_transfer(ao_radio_dma,
- packet,
- &RFDXADDR,
- size,
- DMA_CFG0_WORDSIZE_8 |
- DMA_CFG0_TMODE_SINGLE |
- DMA_CFG0_TRIGGER_RADIO,
- DMA_CFG1_SRCINC_1 |
- DMA_CFG1_DESTINC_0 |
- DMA_CFG1_PRIORITY_HIGH);
- ao_dma_start(ao_radio_dma);
- RFST = RFST_STX;
- __critical while (!ao_radio_done)
- ao_sleep(&ao_radio_done);
- ao_radio_put();
-}
-
-uint8_t
-ao_radio_recv(__xdata void *packet, uint8_t size) __reentrant
-{
- ao_radio_abort = 0;
- ao_radio_get(size - 2);
- ao_dma_set_transfer(ao_radio_dma,
- &RFDXADDR,
- packet,
- size,
- DMA_CFG0_WORDSIZE_8 |
- DMA_CFG0_TMODE_SINGLE |
- DMA_CFG0_TRIGGER_RADIO,
- DMA_CFG1_SRCINC_0 |
- DMA_CFG1_DESTINC_1 |
- DMA_CFG1_PRIORITY_HIGH);
- ao_dma_start(ao_radio_dma);
- RFST = RFST_SRX;
-
- /* Wait for DMA to be done, for the radio receive process to
- * get aborted or for a receive timeout to fire
- */
- __critical while (!ao_radio_dma_done && !ao_radio_abort)
- if (ao_sleep(&ao_radio_dma_done))
- break;
-
- /* If recv was aborted, clean up by stopping the DMA engine
- * and idling the radio
- */
- if (!ao_radio_dma_done) {
- ao_dma_abort(ao_radio_dma);
- ao_radio_idle();
- }
- ao_radio_put();
- return ao_radio_dma_done;
-}
-
-/*
- * Wake up a task waiting to receive a radio packet
- * and tell them to abort the transfer
- */
-
-void
-ao_radio_recv_abort(void)
-{
- ao_radio_abort = 1;
- ao_wakeup(&ao_radio_dma_done);
-}
-
-__xdata ao_radio_rdf_value = 0x55;
-
-void
-ao_radio_rdf(int ms)
-{
- 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);
- ao_radio_done = 0;
- for (i = 0; i < sizeof (rdf_setup); i += 2)
- RF[rdf_setup[i]] = rdf_setup[i+1];
-
- ao_dma_set_transfer(ao_radio_dma,
- &ao_radio_rdf_value,
- &RFDXADDR,
- pkt_len,
- DMA_CFG0_WORDSIZE_8 |
- DMA_CFG0_TMODE_SINGLE |
- DMA_CFG0_TRIGGER_RADIO,
- DMA_CFG1_SRCINC_0 |
- DMA_CFG1_DESTINC_0 |
- DMA_CFG1_PRIORITY_HIGH);
- ao_dma_start(ao_radio_dma);
- RFST = RFST_STX;
- __critical while (!ao_radio_done && !ao_radio_abort)
- ao_sleep(&ao_radio_done);
- if (!ao_radio_done) {
- ao_dma_abort(ao_radio_dma);
- ao_radio_idle();
- }
- ao_radio_set_packet();
- ao_radio_put();
-}
-
-void
-ao_radio_rdf_abort(void)
-{
- ao_radio_abort = 1;
- ao_wakeup(&ao_radio_done);
-}
-
-
-/* Output carrier */
-void
-ao_radio_test(void)
-{
- uint8_t mode = 2;
- static __xdata radio_on;
- ao_cmd_white();
- if (ao_cmd_lex_c != '\n') {
- ao_cmd_decimal();
- mode = (uint8_t) ao_cmd_lex_u32;
- }
- mode++;
- if ((mode & 2) && !radio_on) {
-#if HAS_MONITOR
- ao_set_monitor(0);
-#endif
-#if PACKET_HAS_SLAVE
- ao_packet_slave_stop();
-#endif
- ao_radio_get(0xff);
- RFST = RFST_STX;
- radio_on = 1;
- }
- if (mode == 3) {
- printf ("Hit a character to stop..."); flush();
- getchar();
- putchar('\n');
- }
- if ((mode & 1) && radio_on) {
- ao_radio_idle();
- ao_radio_put();
- radio_on = 0;
- }
-}
-
-__code struct ao_cmds ao_radio_cmds[] = {
- { ao_radio_test, "C <1 start, 0 stop, none both>\0Radio carrier test" },
- { 0, NULL },
-};
-
-void
-ao_radio_init(void)
-{
- uint8_t i;
- for (i = 0; i < sizeof (radio_setup); i += 2)
- RF[radio_setup[i]] = radio_setup[i+1];
- ao_radio_set_packet();
- ao_radio_dma_done = 1;
- ao_radio_dma = ao_dma_alloc(&ao_radio_dma_done);
- RFIF = 0;
- RFIM = RFIM_IM_TIMEOUT|RFIM_IM_DONE;
- IEN2 |= IEN2_RFIE;
- ao_cmd_register(&ao_radio_cmds[0]);
-}
--- /dev/null
+/*
+ * 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]);
+}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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"
-
-/* Use the watchdog timer to force a complete reboot
- */
-void
-ao_reboot(void)
-{
- WDCTL = WDCTL_EN | WDCTL_MODE_WATCHDOG | WDCTL_INT_32768;
- ao_delay(AO_SEC_TO_TICKS(2));
- ao_panic(AO_PANIC_REBOOT);
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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 BIT(i,x) ((x) ? (1 << (i)) : 0)
-#define MORSE1(a) (1 | BIT(3,a))
-#define MORSE2(a,b) (2 | BIT(3,a) | BIT(4,b))
-#define MORSE3(a,b,c) (3 | BIT(3,a) | BIT(4,b) | BIT(5,c))
-#define MORSE4(a,b,c,d) (4 | BIT(3,a) | BIT(4,b) | BIT(5,c) | BIT(6,d))
-#define MORSE5(a,b,c,d,e) (5 | BIT(3,a) | BIT(4,b) | BIT(5,c) | BIT(6,d) | BIT(7,e))
-
-static const uint8_t flight_reports[] = {
- MORSE3(0,0,0), /* startup, 'S' */
- MORSE2(0,0), /* idle 'I' */
- MORSE4(0,1,1,0), /* pad 'P' */
- MORSE4(1,0,0,0), /* boost 'B' */
- MORSE4(0,0,1,0), /* fast 'F' */
- MORSE4(1,0,1,0), /* coast 'C' */
- MORSE3(1,0,0), /* drogue 'D' */
- MORSE2(1,1), /* main 'M' */
- MORSE4(0,1,0,0), /* landed 'L' */
- MORSE4(1,0,0,1), /* invalid 'X' */
-};
-
-#if HAS_BEEP
-#define low(time) ao_beep_for(AO_BEEP_LOW, time)
-#define mid(time) ao_beep_for(AO_BEEP_MID, time)
-#define high(time) ao_beep_for(AO_BEEP_HIGH, time)
-#else
-#define low(time) ao_led_for(AO_LED_GREEN, time)
-#define mid(time) ao_led_for(AO_LED_RED, time)
-#define high(time) ao_led_for(AO_LED_GREEN|AO_LED_RED, time)
-#endif
-#define pause(time) ao_delay(time)
-
-static __pdata enum ao_flight_state ao_report_state;
-
-static void
-ao_report_beep(void) __reentrant
-{
- uint8_t r = flight_reports[ao_flight_state];
- uint8_t l = r & 7;
-
- if (!r)
- return;
- while (l--) {
- if (r & 8)
- mid(AO_MS_TO_TICKS(600));
- else
- mid(AO_MS_TO_TICKS(200));
- pause(AO_MS_TO_TICKS(200));
- r >>= 1;
- }
- pause(AO_MS_TO_TICKS(400));
-}
-
-static void
-ao_report_digit(uint8_t digit) __reentrant
-{
- if (!digit) {
- mid(AO_MS_TO_TICKS(500));
- pause(AO_MS_TO_TICKS(200));
- } else {
- while (digit--) {
- mid(AO_MS_TO_TICKS(200));
- pause(AO_MS_TO_TICKS(200));
- }
- }
- pause(AO_MS_TO_TICKS(300));
-}
-
-static void
-ao_report_altitude(void)
-{
- __pdata int16_t agl = ao_max_height;
- __xdata uint8_t digits[10];
- __pdata uint8_t ndigits, i;
-
- if (agl < 0)
- agl = 0;
- ndigits = 0;
- do {
- digits[ndigits++] = agl % 10;
- agl /= 10;
- } while (agl);
-
- for (;;) {
- ao_report_beep();
- i = ndigits;
- do
- ao_report_digit(digits[--i]);
- while (i != 0);
- pause(AO_SEC_TO_TICKS(5));
- }
-}
-
-#if HAS_IGNITE
-static uint8_t
-ao_report_igniter_ready(enum ao_igniter igniter)
-{
- return ao_igniter_status(igniter) == ao_igniter_ready ? 1 : 0;
-}
-
-static void
-ao_report_continuity(void) __reentrant
-{
- uint8_t c = (ao_report_igniter_ready(ao_igniter_drogue) |
- (ao_report_igniter_ready(ao_igniter_main) << 1));
- if (c) {
- while (c--) {
- high(AO_MS_TO_TICKS(25));
- pause(AO_MS_TO_TICKS(100));
- }
- } else {
- c = 10;
- while (c--) {
- high(AO_MS_TO_TICKS(20));
- low(AO_MS_TO_TICKS(20));
- }
- }
- if (ao_log_full()) {
- pause(AO_MS_TO_TICKS(100));
- c = 2;
- while (c--) {
- low(AO_MS_TO_TICKS(100));
- mid(AO_MS_TO_TICKS(100));
- high(AO_MS_TO_TICKS(100));
- mid(AO_MS_TO_TICKS(100));
- }
- }
- c = 50;
- while (c-- && ao_flight_state == ao_flight_pad)
- pause(AO_MS_TO_TICKS(100));
-}
-#endif
-
-void
-ao_report(void)
-{
- ao_report_state = ao_flight_state;
- for(;;) {
- if (ao_flight_state == ao_flight_landed)
- ao_report_altitude();
- ao_report_beep();
-#if HAS_IGNITE
- if (ao_flight_state == ao_flight_idle)
- ao_report_continuity();
- while (ao_flight_state == ao_flight_pad)
- ao_report_continuity();
-#endif
- __critical {
- while (ao_report_state == ao_flight_state)
- ao_sleep(DATA_TO_XDATA(&ao_flight_state));
- ao_report_state = ao_flight_state;
- }
- }
-}
-
-static __xdata struct ao_task ao_report_task;
-
-void
-ao_report_init(void)
-{
- ao_add_task(&ao_report_task, ao_report, "report");
-}
+++ /dev/null
-/*
- * 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.
- */
-
-#include "ao.h"
-
-__code __at (0x00a0) uint16_t ao_romconfig_version = AO_ROMCONFIG_VERSION;
-__code __at (0x00a2) uint16_t ao_romconfig_check = ~AO_ROMCONFIG_VERSION;
-__code __at (0x00a4) uint16_t ao_serial_number = 0;
-/*
- * For 434.550MHz, the frequency value is:
- *
- * 434.550e6 / (24e6 / 2**16) = 1186611.2
- *
- * This value is stored in a const variable so that
- * ao-load can change it during programming for
- * devices that have no eeprom for config data.
- */
-__code __at (0x00a6) uint32_t ao_radio_cal = 1186611;
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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 __xdata volatile uint16_t ao_rssi_time;
-static __pdata volatile uint16_t ao_rssi_delay;
-static __pdata uint8_t ao_rssi_led;
-
-void
-ao_rssi(void)
-{
- for (;;) {
- while ((int16_t) (ao_time() - ao_rssi_time) > AO_SEC_TO_TICKS(3))
- ao_sleep(&ao_rssi_time);
- ao_led_for(ao_rssi_led, AO_MS_TO_TICKS(100));
- ao_delay(ao_rssi_delay);
- }
-}
-
-void
-ao_rssi_set(int rssi_value)
-{
- if (rssi_value > 0)
- rssi_value = 0;
- ao_rssi_delay = AO_MS_TO_TICKS((-rssi_value) * 5);
- ao_rssi_time = ao_time();
- ao_wakeup(&ao_rssi_time);
-}
-
-__xdata struct ao_task ao_rssi_task;
-
-void
-ao_rssi_init(uint8_t rssi_led)
-{
- ao_rssi_led = rssi_led;
- ao_rssi_delay = 0;
- ao_add_task(&ao_rssi_task, ao_rssi, "rssi");
-}
+++ /dev/null
-/*
- * 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_FLIGHT_TEST
-#include "ao.h"
-#endif
-
-/*
- * Current sensor values
- */
-
-__pdata uint16_t ao_sample_tick; /* time of last data */
-__pdata int16_t ao_sample_pres;
-__pdata int16_t ao_sample_alt;
-__pdata int16_t ao_sample_height;
-#if HAS_ACCEL
-__pdata int16_t ao_sample_accel;
-#endif
-
-__data uint8_t ao_sample_adc;
-
-/*
- * Sensor calibration values
- */
-
-__pdata int16_t ao_ground_pres; /* startup pressure */
-__pdata int16_t ao_ground_height; /* MSL of ao_ground_pres */
-
-#if HAS_ACCEL
-__pdata int16_t ao_ground_accel; /* startup acceleration */
-__pdata int16_t ao_accel_2g; /* factory accel calibration */
-__pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */
-#endif
-
-static __pdata uint8_t ao_preflight; /* in preflight mode */
-
-static __pdata uint16_t nsamples;
-__pdata int32_t ao_sample_pres_sum;
-#if HAS_ACCEL
-__pdata int32_t ao_sample_accel_sum;
-#endif
-
-static void
-ao_sample_preflight(void)
-{
- /* startup state:
- *
- * Collect 512 samples of acceleration and pressure
- * data and average them to find the resting values
- */
- if (nsamples < 512) {
-#if HAS_ACCEL
- ao_sample_accel_sum += ao_sample_accel;
-#endif
- ao_sample_pres_sum += ao_sample_pres;
- ++nsamples;
- } else {
- ao_config_get();
-#if HAS_ACCEL
- ao_ground_accel = ao_sample_accel_sum >> 9;
- ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g;
- ao_accel_scale = to_fix32(GRAVITY * 2 * 16) / ao_accel_2g;
-#endif
- ao_ground_pres = ao_sample_pres_sum >> 9;
- ao_ground_height = ao_pres_to_altitude(ao_ground_pres);
- ao_preflight = FALSE;
- }
-}
-
-uint8_t
-ao_sample(void)
-{
- ao_wakeup(DATA_TO_XDATA(&ao_sample_adc));
- ao_sleep(DATA_TO_XDATA(&ao_adc_head));
- while (ao_sample_adc != ao_adc_head) {
- __xdata struct ao_adc *ao_adc;
-
- /* Capture a sample */
- ao_adc = &ao_adc_ring[ao_sample_adc];
- ao_sample_tick = ao_adc->tick;
- ao_sample_pres = ao_adc->pres;
- ao_sample_alt = ao_pres_to_altitude(ao_sample_pres);
- ao_sample_height = ao_sample_alt - ao_ground_height;
-#if HAS_ACCEL
- ao_sample_accel = ao_adc->accel;
-#if HAS_ACCEL_REF
- /*
- * Ok, the math here is a bit tricky.
- *
- * ao_sample_accel: ADC output for acceleration
- * ao_accel_ref: ADC output for the 5V reference.
- * ao_cook_accel: Corrected acceleration value
- * Vcc: 3.3V supply to the CC1111
- * Vac: 5V supply to the accelerometer
- * accel: input voltage to accelerometer ADC pin
- * ref: input voltage to 5V reference ADC pin
- *
- *
- * Measured acceleration is ratiometric to Vcc:
- *
- * ao_sample_accel accel
- * ------------ = -----
- * 32767 Vcc
- *
- * Measured 5v reference is also ratiometric to Vcc:
- *
- * ao_accel_ref ref
- * ------------ = -----
- * 32767 Vcc
- *
- *
- * ao_accel_ref = 32767 * (ref / Vcc)
- *
- * Acceleration is measured ratiometric to the 5V supply,
- * so what we want is:
- *
- * ao_cook_accel accel
- * ------------- = -----
- * 32767 ref
- *
- *
- * accel Vcc
- * = ----- * ---
- * Vcc ref
- *
- * ao_sample_accel 32767
- * = ------------ * ------------
- * 32767 ao_accel_ref
- *
- * Multiply through by 32767:
- *
- * ao_sample_accel * 32767
- * ao_cook_accel = --------------------
- * ao_accel_ref
- *
- * Now, the tricky part. Getting this to compile efficiently
- * and keeping all of the values in-range.
- *
- * First off, we need to use a shift of 16 instead of * 32767 as SDCC
- * does the obvious optimizations for byte-granularity shifts:
- *
- * ao_cook_accel = (ao_sample_accel << 16) / ao_accel_ref
- *
- * Next, lets check our input ranges:
- *
- * 0 <= ao_sample_accel <= 0x7fff (singled ended ADC conversion)
- * 0x7000 <= ao_accel_ref <= 0x7fff (the 5V ref value is close to 0x7fff)
- *
- * Plugging in our input ranges, we get an output range of 0 - 0x12490,
- * which is 17 bits. That won't work. If we take the accel ref and shift
- * by a bit, we'll change its range:
- *
- * 0xe000 <= ao_accel_ref<<1 <= 0xfffe
- *
- * ao_cook_accel = (ao_sample_accel << 16) / (ao_accel_ref << 1)
- *
- * Now the output range is 0 - 0x9248, which nicely fits in 16 bits. It
- * is, however, one bit too large for our signed computations. So, we
- * take the result and shift that by a bit:
- *
- * ao_cook_accel = ((ao_sample_accel << 16) / (ao_accel_ref << 1)) >> 1
- *
- * This finally creates an output range of 0 - 0x4924. As the ADC only
- * provides 11 bits of data, we haven't actually lost any precision,
- * just dropped a bit of noise off the low end.
- */
- ao_sample_accel = (uint16_t) ((((uint32_t) ao_sample_accel << 16) / (ao_accel_ref[ao_sample_adc] << 1))) >> 1;
- if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP)
- ao_sample_accel = 0x7fff - ao_sample_accel;
- ao_adc->accel = ao_sample_accel;
-#endif
-#endif
-
- if (ao_preflight)
- ao_sample_preflight();
- else
- ao_kalman();
- ao_sample_adc = ao_adc_ring_next(ao_sample_adc);
- }
- return !ao_preflight;
-}
-
-void
-ao_sample_init(void)
-{
- nsamples = 0;
- ao_sample_pres_sum = 0;
- ao_sample_pres = 0;
-#if HAS_ACCEL
- ao_sample_accel_sum = 0;
- ao_sample_accel = 0;
-#endif
- ao_sample_adc = ao_adc_head;
- ao_preflight = TRUE;
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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_fifo ao_usart1_rx_fifo;
-volatile __xdata struct ao_fifo ao_usart1_tx_fifo;
-
-void
-ao_serial_rx1_isr(void) __interrupt 3
-{
- if (!ao_fifo_full(ao_usart1_rx_fifo))
- ao_fifo_insert(ao_usart1_rx_fifo, U1DBUF);
- 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, U1DBUF);
- }
-}
-
-void
-ao_serial_tx1_isr(void) __interrupt 14
-{
- UTX1IF = 0;
- ao_serial_tx1_started = 0;
- ao_serial_tx1_start();
- ao_wakeup(&ao_usart1_tx_fifo);
-}
-
-char
-ao_serial_getchar(void) __critical
-{
- char c;
- while (ao_fifo_empty(ao_usart1_rx_fifo))
- ao_sleep(&ao_usart1_rx_fifo);
- ao_fifo_remove(ao_usart1_rx_fifo, c);
- return c;
-}
-
-#if USE_SERIAL_STDIN
-char
-ao_serial_pollchar(void) __critical
-{
- char c;
- if (ao_fifo_empty(ao_usart1_rx_fifo))
- return AO_READ_AGAIN;
- ao_fifo_remove(ao_usart1_rx_fifo,c);
- return c;
-}
-#endif
-
-void
-ao_serial_putchar(char c) __critical
-{
- 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();
-}
-
-void
-ao_serial_drain(void) __critical
-{
- while (!ao_fifo_empty(ao_usart1_tx_fifo))
- ao_sleep(&ao_usart1_tx_fifo);
-}
-
-static __code struct {
- uint8_t baud;
- uint8_t gcr;
-} ao_serial_speeds[] = {
- /* [AO_SERIAL_SPEED_4800] = */ {
- /* .baud = */ 163,
- /* .gcr = */ (7 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
- },
- /* [AO_SERIAL_SPEED_9600] = */ {
- /* .baud = */ 163,
- /* .gcr = */ (8 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
- },
- /* [AO_SERIAL_SPEED_19200] = */ {
- /* .baud = */ 163,
- /* .gcr = */ (9 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
- },
- /* [AO_SERIAL_SPEED_57600] = */ {
- /* .baud = */ 59,
- /* .gcr = */ (11 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
- },
-};
-
-void
-ao_serial_set_speed(uint8_t speed)
-{
- ao_serial_drain();
- if (speed > AO_SERIAL_SPEED_57600)
- return;
- U1UCR |= UxUCR_FLUSH;
- U1BAUD = ao_serial_speeds[speed].baud;
- U1GCR = ao_serial_speeds[speed].gcr;
-}
-
-void
-ao_serial_init(void)
-{
-#if HAS_SERIAL_1_ALT_1
- /* Set up the USART pin assignment */
- PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_1;
-
- P2DIR = (P2DIR & ~P2DIR_PRIP0_MASK) | P2DIR_PRIP0_USART1_USART0;
-
- /* Make the USART pins be controlled by the USART */
- P0SEL |= (1 << 5) | (1 << 4);
-#if HAS_SERIAL_1_HW_FLOW
- P0SEL |= (1 << 3) | (1 << 2);
-#endif
-#else
- /* Set up the USART pin assignment */
- PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_2;
-
- P2SEL = (P2SEL & ~(P2SEL_PRI3P1_MASK | P2SEL_PRI2P1_MASK)) |
- (P2SEL_PRI3P1_USART1 | P2SEL_PRI2P1_USART1);
-
- /* Make the USART pins be controlled by the USART */
- P1SEL |= (1 << 6) | (1 << 7);
- P1SEL |= (1 << 5) | (1 << 4);
-#endif
-
- /* UART mode with receiver enabled */
- U1CSR = (UxCSR_MODE_UART | UxCSR_RE);
-
- /* Pick a 4800 baud rate */
- ao_serial_set_speed(AO_SERIAL_SPEED_4800);
-
- /* Reasonable serial parameters */
- U1UCR = (UxUCR_FLUSH |
-#if HAS_SERIAL_1_HW_FLOW
- UxUCR_FLOW_ENABLE |
-#else
- UxUCR_FLOW_DISABLE |
-#endif
- UxUCR_D9_EVEN_PARITY |
- UxUCR_BIT9_8_BITS |
- UxUCR_PARITY_DISABLE |
- UxUCR_SPB_1_STOP_BIT |
- UxUCR_STOP_HIGH |
- UxUCR_START_LOW);
-
- IEN0 |= IEN0_URX1IE;
- IEN2 |= IEN2_UTX1IE;
-}
+++ /dev/null
-/*
- * 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.
- */
-
-#include "ao.h"
-
-/* Shared mutex to protect SPI bus, must cover the entire
- * operation, from CS low to CS high. This means that any SPI
- * user must protect the SPI bus with this mutex
- */
-__xdata uint8_t ao_spi_mutex;
-__xdata uint8_t ao_spi_dma_in_done;
-__xdata uint8_t ao_spi_dma_out_done;
-
-uint8_t ao_spi_dma_out_id;
-uint8_t ao_spi_dma_in_id;
-
-static __xdata uint8_t ao_spi_const = 0xff;
-
-/* Send bytes over SPI.
- *
- * This sets up two DMA engines, one writing the data and another reading
- * bytes coming back. We use the bytes coming back to tell when the transfer
- * is complete, as the transmit register is double buffered and hence signals
- * completion one byte before the transfer is actually complete
- */
-void
-ao_spi_send(void __xdata *block, uint16_t len) __reentrant
-{
- ao_dma_set_transfer(ao_spi_dma_in_id,
- &U0DBUFXADDR,
- &ao_spi_const,
- len,
- DMA_CFG0_WORDSIZE_8 |
- DMA_CFG0_TMODE_SINGLE |
- DMA_CFG0_TRIGGER_URX0,
- DMA_CFG1_SRCINC_0 |
- DMA_CFG1_DESTINC_0 |
- DMA_CFG1_PRIORITY_NORMAL);
-
- ao_dma_set_transfer(ao_spi_dma_out_id,
- block,
- &U0DBUFXADDR,
- len,
- DMA_CFG0_WORDSIZE_8 |
- DMA_CFG0_TMODE_SINGLE |
- DMA_CFG0_TRIGGER_UTX0,
- DMA_CFG1_SRCINC_1 |
- DMA_CFG1_DESTINC_0 |
- DMA_CFG1_PRIORITY_NORMAL);
-
- ao_dma_start(ao_spi_dma_in_id);
- ao_dma_start(ao_spi_dma_out_id);
- ao_dma_trigger(ao_spi_dma_out_id);
- __critical while (!ao_spi_dma_in_done)
- ao_sleep(&ao_spi_dma_in_done);
-}
-
-/* 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
-{
- ao_dma_set_transfer(ao_spi_dma_in_id,
- &U0DBUFXADDR,
- block,
- len,
- DMA_CFG0_WORDSIZE_8 |
- DMA_CFG0_TMODE_SINGLE |
- DMA_CFG0_TRIGGER_URX0,
- DMA_CFG1_SRCINC_0 |
- DMA_CFG1_DESTINC_1 |
- DMA_CFG1_PRIORITY_NORMAL);
-
- ao_dma_set_transfer(ao_spi_dma_out_id,
- &ao_spi_const,
- &U0DBUFXADDR,
- len,
- DMA_CFG0_WORDSIZE_8 |
- DMA_CFG0_TMODE_SINGLE |
- DMA_CFG0_TRIGGER_UTX0,
- DMA_CFG1_SRCINC_0 |
- DMA_CFG1_DESTINC_0 |
- DMA_CFG1_PRIORITY_NORMAL);
-
- ao_dma_start(ao_spi_dma_in_id);
- ao_dma_start(ao_spi_dma_out_id);
- ao_dma_trigger(ao_spi_dma_out_id);
- __critical while (!ao_spi_dma_in_done)
- ao_sleep(&ao_spi_dma_in_done);
-}
-
-/*
- * 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
- */
-
-void
-ao_spi_init(void)
-{
- /* Set up the USART pin assignment */
- PERCFG = (PERCFG & ~PERCFG_U0CFG_ALT_MASK) | PERCFG_U0CFG_ALT_2;
-
- /* Ensure that USART0 takes precidence over USART1 for pins that
- * they share
- */
- P2SEL = (P2SEL & ~P2SEL_PRI3P1_MASK) | P2SEL_PRI3P1_USART0;
-
- /* Make the SPI pins be controlled by the USART peripheral */
- P1SEL |= ((1 << 5) | (1 << 4) | (1 << 3));
-
- /* Set up OUT DMA */
- ao_spi_dma_out_id = ao_dma_alloc(&ao_spi_dma_out_done);
-
- /* Set up IN DMA */
- ao_spi_dma_in_id = ao_dma_alloc(&ao_spi_dma_in_done);
-
- /* Set up the USART.
- *
- * SPI master mode
- */
- U0CSR = (UxCSR_MODE_SPI | UxCSR_RE | UxCSR_MASTER);
-
- /* Set the baud rate and signal parameters
- *
- * The cc1111 is limited to a 24/8 MHz SPI clock.
- * Every peripheral I've ever seen goes faster than that,
- * so set the clock to 3MHz (BAUD_E 17, BAUD_M 0)
- */
- U0BAUD = 0;
- U0GCR = (UxGCR_CPOL_NEGATIVE |
- UxGCR_CPHA_FIRST_EDGE |
- UxGCR_ORDER_MSB |
- (17 << UxGCR_BAUD_E_SHIFT));
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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"
-
-const char const * const ao_state_names[] = {
- "startup", "idle", "pad", "boost", "fast",
- "coast", "drogue", "main", "landed", "invalid"
-};
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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"
-
-/*
- * Basic I/O functions to support SDCC stdio package
- */
-
-#define AO_NUM_STDIOS (HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN)
-
-__xdata struct ao_stdio ao_stdios[AO_NUM_STDIOS];
-__pdata int8_t ao_cur_stdio;
-__pdata int8_t ao_num_stdios;
-
-void
-putchar(char c)
-{
- if (c == '\n')
- (*ao_stdios[ao_cur_stdio].putchar)('\r');
- (*ao_stdios[ao_cur_stdio].putchar)(c);
-}
-
-void
-flush(void)
-{
- if (ao_stdios[ao_cur_stdio].flush)
- ao_stdios[ao_cur_stdio].flush();
-}
-
-__xdata uint8_t ao_stdin_ready;
-
-char
-getchar(void) __reentrant __critical
-{
- char c;
- int8_t stdio = ao_cur_stdio;
-
- for (;;) {
- c = ao_stdios[stdio].pollchar();
- if (c != AO_READ_AGAIN)
- break;
- if (++stdio == ao_num_stdios)
- stdio = 0;
- if (stdio == ao_cur_stdio)
- ao_sleep(&ao_stdin_ready);
- }
- ao_cur_stdio = stdio;
- return c;
-}
-
-uint8_t
-ao_echo(void)
-{
- return ao_stdios[ao_cur_stdio].echo;
-}
-
-int8_t
-ao_add_stdio(char (*pollchar)(void),
- void (*putchar)(char),
- void (*flush)(void)) __reentrant
-{
- if (ao_num_stdios == AO_NUM_STDIOS)
- ao_panic(AO_PANIC_STDIO);
- ao_stdios[ao_num_stdios].pollchar = pollchar;
- ao_stdios[ao_num_stdios].putchar = putchar;
- ao_stdios[ao_num_stdios].flush = flush;
- ao_stdios[ao_num_stdios].echo = 1;
- return ao_num_stdios++;
-}
+++ /dev/null
-/*
- * 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_storage_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
-{
- uint16_t this_len;
- uint16_t this_off;
-
- ao_storage_setup();
- if (pos >= ao_storage_total || pos + len > ao_storage_total)
- return 0;
- while (len) {
-
- /* Compute portion of transfer within
- * a single block
- */
- this_off = (uint16_t) pos & (ao_storage_unit - 1);
- this_len = ao_storage_unit - this_off;
- if (this_len > len)
- this_len = len;
-
- if (!ao_storage_device_read(pos, buf, this_len))
- return 0;
-
- /* See how much is left */
- buf += this_len;
- len -= this_len;
- pos += this_len;
- }
- return 1;
-}
-
-uint8_t
-ao_storage_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
-{
- uint16_t this_len;
- uint16_t this_off;
-
- ao_storage_setup();
- if (pos >= ao_storage_total || pos + len > ao_storage_total)
- return 0;
- while (len) {
-
- /* Compute portion of transfer within
- * a single block
- */
- this_off = (uint16_t) pos & (ao_storage_unit - 1);
- this_len = ao_storage_unit - this_off;
- if (this_len > len)
- this_len = len;
-
- if (!ao_storage_device_write(pos, buf, this_len))
- return 0;
-
- /* See how much is left */
- buf += this_len;
- len -= this_len;
- pos += this_len;
- }
- return 1;
-}
-
-static __xdata uint8_t storage_data[8];
-
-static void
-ao_storage_dump(void) __reentrant
-{
- uint8_t i, j;
-
- ao_cmd_hex();
- if (ao_cmd_status != ao_cmd_success)
- return;
- for (i = 0; ; i += 8) {
- if (ao_storage_read(((uint32_t) (ao_cmd_lex_i) << 8) + i,
- storage_data,
- 8)) {
- ao_cmd_put16((uint16_t) i);
- for (j = 0; j < 8; j++) {
- putchar(' ');
- ao_cmd_put8(storage_data[j]);
- }
- putchar ('\n');
- }
- if (i == 248)
- break;
- }
-}
-
-#if 0
-
-/* not enough space for this today
- */
-static void
-ao_storage_store(void) __reentrant
-{
- uint16_t block;
- uint8_t i;
- uint16_t len;
- static __xdata uint8_t b;
- uint32_t addr;
-
- ao_cmd_hex();
- block = ao_cmd_lex_i;
- ao_cmd_hex();
- i = ao_cmd_lex_i;
- addr = ((uint32_t) block << 8) | i;
- ao_cmd_hex();
- len = ao_cmd_lex_i;
- if (ao_cmd_status != ao_cmd_success)
- return;
- while (len--) {
- ao_cmd_hex();
- if (ao_cmd_status != ao_cmd_success)
- return;
- b = ao_cmd_lex_i;
- ao_storage_write(addr, &b, 1);
- addr++;
- }
-}
-#endif
-
-void
-ao_storage_zap(void) __reentrant
-{
- ao_cmd_hex();
- if (ao_cmd_status != ao_cmd_success)
- return;
- ao_storage_erase((uint32_t) ao_cmd_lex_i << 8);
-}
-
-void
-ao_storage_zapall(void) __reentrant
-{
- uint32_t pos;
-
- ao_cmd_white();
- if (!ao_match_word("DoIt"))
- return;
- for (pos = 0; pos < ao_storage_config; pos += ao_storage_block)
- ao_storage_erase(pos);
-}
-
-void
-ao_storage_info(void) __reentrant
-{
- printf("Storage size: %ld\n", ao_storage_total);
- printf("Storage erase unit: %ld\n", ao_storage_block);
- ao_storage_device_info();
-}
-
-__code struct ao_cmds ao_storage_cmds[] = {
- { ao_storage_info, "f\0Show storage" },
- { ao_storage_dump, "e <block>\0Dump flash" },
-#ifdef HAS_STORAGE_DBG
- { ao_storage_store, "w <block> <start> <len> <data> ...\0Write data to flash" },
-#endif
- { ao_storage_zap, "z <block>\0Erase <block>" },
- { ao_storage_zapall,"Z <key>\0Erase all. <key> is doit with D&I" },
- { 0, NULL },
-};
-
-void
-ao_storage_init(void)
-{
- ao_storage_device_init();
- ao_cmd_register(&ao_storage_cmds[0]);
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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_NO_TASK_INDEX 0xff
-
-__xdata struct ao_task * __xdata ao_tasks[AO_NUM_TASKS];
-__data uint8_t ao_num_tasks;
-__data uint8_t ao_cur_task_index;
-__xdata struct ao_task *__data ao_cur_task;
-
-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)
- ao_panic(AO_PANIC_NO_TASK);
- for (task_id = 1; task_id != 0; task_id++) {
- for (t = 0; t < ao_num_tasks; t++)
- if (ao_tasks[t]->task_id == task_id)
- break;
- if (t == ao_num_tasks)
- break;
- }
- ao_tasks[ao_num_tasks++] = task;
- task->task_id = task_id;
- task->name = name;
- /*
- * 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;
-}
-
-/* Task switching function. This must not use any stack variables */
-void
-ao_yield(void) __naked
-{
-
- /* 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;
-
- 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);
- }
-
- /* Empty the stack; might as well let interrupts have the whole thing */
- SP = AO_STACK_START - 1;
-
- /* Find a task to run. If there isn't any runnable task,
- * this loop will run forever, which is just fine
- */
- {
- __pdata uint8_t ao_next_task_index = ao_cur_task_index;
- for (;;) {
- ++ao_next_task_index;
- if (ao_next_task_index == ao_num_tasks)
- ao_next_task_index = 0;
-
- ao_cur_task = ao_tasks[ao_next_task_index];
- if (ao_cur_task->wchan == NULL) {
- ao_cur_task_index = ao_next_task_index;
- break;
- }
-
- /* Check if the alarm is set for a time which has passed */
- if (ao_cur_task->alarm &&
- (int16_t) (ao_time() - ao_cur_task->alarm) >= 0) {
- ao_cur_task_index = ao_next_task_index;
- break;
- }
-
- /* Enter lower power mode when there isn't anything to do */
- if (ao_next_task_index == ao_cur_task_index)
- PCON = PCON_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;
-}
-
-uint8_t
-ao_sleep(__xdata void *wchan)
-{
- __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;
- }
- return 0;
-}
-
-void
-ao_wakeup(__xdata void *wchan)
-{
- uint8_t i;
-
- for (i = 0; i < ao_num_tasks; i++)
- if (ao_tasks[i]->wchan == wchan)
- ao_tasks[i]->wchan = NULL;
-}
-
-void
-ao_alarm(uint16_t delay)
-{
- /* Make sure we sleep *at least* delay ticks, which means adding
- * one to account for the fact that we may be close to the next tick
- */
- if (!(ao_cur_task->alarm = ao_time() + delay + 1))
- ao_cur_task->alarm = 1;
-}
-
-void
-ao_exit(void) __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 */
-}
-
-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",
- task->name,
- (int16_t) task->wchan,
- (task->stack[pc_loc]) | (task->stack[pc_loc+1] << 8));
- }
-}
-
-void
-ao_start_scheduler(void)
-{
- ao_cur_task_index = AO_NO_TASK_INDEX;
- ao_cur_task = NULL;
- ao_yield();
-}
+++ /dev/null
-/*
- * 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_NONE; /* until we actually log stuff */
-
-void
-main(void)
-{
- ao_clock_init();
-
- /* Turn on the LED until the system is stable */
- ao_led_init(LEDS_AVAILABLE);
- ao_led_on(AO_LED_RED);
- ao_timer_init();
-#if HAS_BEEP
- ao_beep_init();
-#endif
- ao_cmd_init();
-#if HAS_EEPROM
- ao_spi_init();
- ao_storage_init();
-#endif
- ao_usb_init();
- ao_monitor_init(AO_LED_GREEN, TRUE);
- ao_rssi_init(AO_LED_RED);
- ao_radio_init();
- ao_packet_master_init();
- ao_btm_init();
-#if HAS_DBG
- ao_dbg_init();
-#endif
- ao_config_init();
- ao_start_scheduler();
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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
-main(void)
-{
- ao_clock_init();
-
- /* Turn on the LED until the system is stable */
- ao_led_init(LEDS_AVAILABLE);
- ao_led_on(AO_LED_RED);
- ao_timer_init();
- ao_cmd_init();
- ao_usb_init();
- ao_monitor_init(AO_LED_GREEN, TRUE);
- ao_rssi_init(AO_LED_RED);
- ao_radio_init();
- ao_packet_master_init();
-#if HAS_DBG
- ao_dbg_init();
-#endif
- ao_config_init();
- ao_start_scheduler();
-}
--- /dev/null
+/*
+ * 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_pins.h"
+
+void
+main(void)
+{
+ ao_clock_init();
+
+ /* Turn on the red LED until the system is stable */
+ ao_led_init(LEDS_AVAILABLE);
+ ao_led_on(AO_LED_RED);
+
+ ao_timer_init();
+ ao_adc_init();
+ ao_beep_init();
+ ao_cmd_init();
+ ao_spi_init();
+ ao_storage_init();
+ ao_usb_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();
+}
+++ /dev/null
-/*
- * 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_TELEM_H_
-#define _AO_TELEM_H_
-
-#define AO_TELEMETRY_VERSION 4
-
-/*
- * Telemetry version 4 and higher format:
- *
- * General header fields
- *
- * Name Value
- *
- * VERSION Telemetry version number (4 or more). Must be first.
- * c Callsign (string, no spaces allowed)
- * n Flight unit serial number (integer)
- * f Flight number (integer)
- * r Packet RSSI value (integer)
- * s Flight computer state (string, no spaces allowed)
- * t Flight computer clock (integer in centiseconds)
- */
-
-#define AO_TELEM_VERSION "VERSION"
-#define AO_TELEM_CALL "c"
-#define AO_TELEM_SERIAL "n"
-#define AO_TELEM_FLIGHT "f"
-#define AO_TELEM_RSSI "r"
-#define AO_TELEM_STATE "s"
-#define AO_TELEM_TICK "t"
-
-/*
- * Raw sensor values
- *
- * Name Value
- * r_a Accelerometer reading (integer)
- * r_b Barometer reading (integer)
- * r_t Thermometer reading (integer)
- * r_v Battery reading (integer)
- * r_d Drogue continuity (integer)
- * r_m Main continuity (integer)
- */
-
-#define AO_TELEM_RAW_ACCEL "r_a"
-#define AO_TELEM_RAW_BARO "r_b"
-#define AO_TELEM_RAW_THERMO "r_t"
-#define AO_TELEM_RAW_BATT "r_v"
-#define AO_TELEM_RAW_DROGUE "r_d"
-#define AO_TELEM_RAW_MAIN "r_m"
-
-/*
- * Sensor calibration values
- *
- * Name Value
- * c_a Ground accelerometer reading (integer)
- * c_b Ground barometer reading (integer)
- * c_p Accelerometer reading for +1g
- * c_m Accelerometer reading for -1g
- */
-
-#define AO_TELEM_CAL_ACCEL_GROUND "c_a"
-#define AO_TELEM_CAL_BARO_GROUND "c_b"
-#define AO_TELEM_CAL_ACCEL_PLUS "c_p"
-#define AO_TELEM_CAL_ACCEL_MINUS "c_m"
-
-/*
- * Kalman state values
- *
- * Name Value
- * k_h Height above pad (integer, meters)
- * k_s Vertical speeed (integer, m/s * 16)
- * k_a Vertical acceleration (integer, m/s² * 16)
- */
-
-#define AO_TELEM_KALMAN_HEIGHT "k_h"
-#define AO_TELEM_KALMAN_SPEED "k_s"
-#define AO_TELEM_KALMAN_ACCEL "k_a"
-
-/*
- * Ad-hoc flight values
- *
- * Name Value
- * a_a Acceleration (integer, sensor units)
- * a_s Speed (integer, integrated acceleration value)
- * a_b Barometer reading (integer, sensor units)
- */
-
-#define AO_TELEM_ADHOC_ACCEL "a_a"
-#define AO_TELEM_ADHOC_SPEED "a_s"
-#define AO_TELEM_ADHOC_BARO "a_b"
-
-/*
- * GPS values
- *
- * Name Value
- * g GPS state (string):
- * l locked
- * u unlocked
- * e error (missing or broken)
- * g_n Number of sats used in solution
- * g_ns Latitude (degrees * 10e7)
- * g_ew Longitude (degrees * 10e7)
- * g_a Altitude (integer meters)
- * g_Y GPS year (integer)
- * g_M GPS month (integer - 1-12)
- * g_D GPS day (integer - 1-31)
- * g_h GPS hour (integer - 0-23)
- * g_m GPS minute (integer - 0-59)
- * g_s GPS second (integer - 0-59)
- * g_v GPS vertical speed (integer, cm/sec)
- * g_g GPS horizontal speed (integer, cm/sec)
- * g_c GPS course (integer, 0-359)
- * g_hd GPS hdop (integer * 10)
- * g_vd GPS vdop (integer * 10)
- * g_he GPS h error (integer)
- * g_ve GPS v error (integer)
- */
-
-#define AO_TELEM_GPS_STATE "g"
-#define AO_TELEM_GPS_STATE_LOCKED 'l'
-#define AO_TELEM_GPS_STATE_UNLOCKED 'u'
-#define AO_TELEM_GPS_STATE_ERROR 'e'
-#define AO_TELEM_GPS_NUM_SAT "g_n"
-#define AO_TELEM_GPS_LATITUDE "g_ns"
-#define AO_TELEM_GPS_LONGITUDE "g_ew"
-#define AO_TELEM_GPS_ALTITUDE "g_a"
-#define AO_TELEM_GPS_YEAR "g_Y"
-#define AO_TELEM_GPS_MONTH "g_M"
-#define AO_TELEM_GPS_DAY "g_D"
-#define AO_TELEM_GPS_HOUR "g_h"
-#define AO_TELEM_GPS_MINUTE "g_m"
-#define AO_TELEM_GPS_SECOND "g_s"
-#define AO_TELEM_GPS_VERTICAL_SPEED "g_v"
-#define AO_TELEM_GPS_HORIZONTAL_SPEED "g_g"
-#define AO_TELEM_GPS_COURSE "g_c"
-#define AO_TELEM_GPS_HDOP "g_hd"
-#define AO_TELEM_GPS_VDOP "g_vd"
-#define AO_TELEM_GPS_HERROR "g_he"
-#define AO_TELEM_GPS_VERROR "g_ve"
-
-/*
- * GPS satellite values
- *
- * Name Value
- * s_n Number of satellites reported (integer)
- * s_v0 Space vehicle ID (integer) for report 0
- * s_c0 C/N0 number (integer) for report 0
- * s_v1 Space vehicle ID (integer) for report 1
- * s_c1 C/N0 number (integer) for report 1
- * ...
- */
-
-#define AO_TELEM_SAT_NUM "s_n"
-#define AO_TELEM_SAT_SVID "s_v"
-#define AO_TELEM_SAT_C_N_0 "s_c"
-
-#endif /* _AO_TELEM_H_ */
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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_pins.h"
-
-void
-main(void)
-{
- /*
- * Reduce the transient on the ignite pins at startup by
- * pulling the pins low as soon as possible at power up
- */
- ao_ignite_set_pins();
-
- ao_clock_init();
-
- /* Turn on the red LED until the system is stable */
- ao_led_init(LEDS_AVAILABLE);
- ao_led_on(AO_LED_RED);
-
- /* A hack -- look at the SPI clock pin, if it's sitting at
- * ground, then we force the computer to idle mode instead of
- * flight mode
- */
- if (P1_3 == 0) {
- ao_flight_force_idle = 1;
- while (P1_3 == 0)
- ;
- }
- ao_timer_init();
- ao_adc_init();
- ao_beep_init();
- ao_cmd_init();
- ao_spi_init();
- ao_storage_init();
- ao_flight_init();
- ao_log_init();
- ao_report_init();
- ao_usb_init();
- ao_serial_init();
- ao_gps_init();
- ao_gps_report_init();
- ao_telemetry_init();
- ao_radio_init();
- ao_packet_slave_init(FALSE);
- ao_igniter_init();
-#if HAS_DBG
- ao_dbg_init();
-#endif
-#if HAS_COMPANION
- ao_companion_init();
-#endif
- ao_config_init();
- ao_start_scheduler();
-}
+++ /dev/null
-/*
- * 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 __pdata uint16_t ao_telemetry_interval;
-static __pdata int8_t ao_telemetry_config_max;
-static __pdata int8_t ao_telemetry_config_cur;
-#if HAS_GPS
-static __pdata int8_t ao_telemetry_loc_cur;
-static __pdata int8_t ao_telemetry_sat_cur;
-#endif
-#if HAS_COMPANION
-static __pdata int8_t ao_telemetry_companion_max;
-static __pdata int8_t ao_telemetry_companion_cur;
-#endif
-static __pdata uint8_t ao_rdf = 0;
-static __pdata uint16_t ao_rdf_time;
-
-#define AO_RDF_INTERVAL_TICKS AO_SEC_TO_TICKS(5)
-#define AO_RDF_LENGTH_MS 500
-
-#if defined(TELEMETRUM_V_0_1) || defined(TELEMETRUM_V_0_2) || defined(TELEMETRUM_V_1_0) || defined(TELEMETRUM_V_1_1)
-#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELEMETRUM
-#endif
-
-#if defined(TELEMINI_V_1_0)
-#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELEMINI
-#endif
-
-#if defined(TELENANO_V_0_1)
-#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELENANO
-#endif
-
-static __xdata union ao_telemetry_all telemetry;
-
-/* Send sensor packet */
-static void
-ao_send_sensor(void)
-{
- uint8_t sample;
- sample = ao_sample_adc;
-
- telemetry.generic.tick = ao_adc_ring[sample].tick;
- telemetry.generic.type = AO_TELEMETRY_SENSOR;
-
- telemetry.sensor.state = ao_flight_state;
-#if HAS_ACCEL
- telemetry.sensor.accel = ao_adc_ring[sample].accel;
-#else
- telemetry.sensor.accel = 0;
-#endif
- telemetry.sensor.pres = ao_adc_ring[sample].pres;
- telemetry.sensor.temp = ao_adc_ring[sample].temp;
- telemetry.sensor.v_batt = ao_adc_ring[sample].v_batt;
-#if HAS_IGNITE
- telemetry.sensor.sense_d = ao_adc_ring[sample].sense_d;
- telemetry.sensor.sense_m = ao_adc_ring[sample].sense_m;
-#else
- telemetry.sensor.sense_d = 0;
- telemetry.sensor.sense_m = 0;
-#endif
-
- telemetry.sensor.acceleration = ao_accel;
- telemetry.sensor.speed = ao_speed;
- telemetry.sensor.height = ao_height;
-
- telemetry.sensor.ground_pres = ao_ground_pres;
-#if HAS_ACCEL
- telemetry.sensor.ground_accel = ao_ground_accel;
- telemetry.sensor.accel_plus_g = ao_config.accel_plus_g;
- telemetry.sensor.accel_minus_g = ao_config.accel_minus_g;
-#else
- telemetry.sensor.ground_accel = 0;
- telemetry.sensor.accel_plus_g = 0;
- telemetry.sensor.accel_minus_g = 0;
-#endif
-
- ao_radio_send(&telemetry, sizeof (telemetry));
-}
-
-static void
-ao_send_configuration(void)
-{
- if (--ao_telemetry_config_cur <= 0)
- {
- telemetry.generic.type = AO_TELEMETRY_CONFIGURATION;
- telemetry.configuration.device = AO_idProduct_NUMBER;
- telemetry.configuration.flight = ao_log_full() ? 0 : ao_flight_number;
- telemetry.configuration.config_major = AO_CONFIG_MAJOR;
- telemetry.configuration.config_minor = AO_CONFIG_MINOR;
- telemetry.configuration.apogee_delay = ao_config.apogee_delay;
- telemetry.configuration.main_deploy = ao_config.main_deploy;
- telemetry.configuration.flight_log_max = ao_config.flight_log_max >> 10;
- memcpy (telemetry.configuration.callsign,
- ao_config.callsign,
- AO_MAX_CALLSIGN);
- memcpy (telemetry.configuration.version,
- ao_version,
- AO_MAX_VERSION);
- ao_radio_send(&telemetry, sizeof (telemetry));
- ao_telemetry_config_cur = ao_telemetry_config_max;
- }
-}
-
-#if HAS_GPS
-static void
-ao_send_location(void)
-{
- if (--ao_telemetry_loc_cur <= 0)
- {
- telemetry.generic.type = AO_TELEMETRY_LOCATION;
- ao_mutex_get(&ao_gps_mutex);
- memcpy(&telemetry.location.flags,
- &ao_gps_data.flags,
- 26);
- ao_mutex_put(&ao_gps_mutex);
- ao_radio_send(&telemetry, sizeof (telemetry));
- ao_telemetry_loc_cur = ao_telemetry_config_max;
- }
-}
-
-static void
-ao_send_satellite(void)
-{
- if (--ao_telemetry_sat_cur <= 0)
- {
- telemetry.generic.type = AO_TELEMETRY_SATELLITE;
- ao_mutex_get(&ao_gps_mutex);
- telemetry.satellite.channels = ao_gps_tracking_data.channels;
- memcpy(&telemetry.satellite.sats,
- &ao_gps_tracking_data.sats,
- AO_MAX_GPS_TRACKING * sizeof (struct ao_telemetry_satellite_info));
- ao_mutex_put(&ao_gps_mutex);
- ao_radio_send(&telemetry, sizeof (telemetry));
- ao_telemetry_sat_cur = ao_telemetry_config_max;
- }
-}
-#endif
-
-#if HAS_COMPANION
-static void
-ao_send_companion(void)
-{
- if (--ao_telemetry_companion_cur <= 0) {
- telemetry.generic.type = AO_TELEMETRY_COMPANION;
- telemetry.companion.board_id = ao_companion_setup.board_id;
- telemetry.companion.update_period = ao_companion_setup.update_period;
- telemetry.companion.channels = ao_companion_setup.channels;
- ao_mutex_get(&ao_companion_mutex);
- memcpy(&telemetry.companion.companion_data,
- ao_companion_data,
- ao_companion_setup.channels * 2);
- ao_mutex_put(&ao_companion_mutex);
- ao_radio_send(&telemetry, sizeof (telemetry));
- ao_telemetry_companion_cur = ao_telemetry_companion_max;
- }
-}
-#endif
-
-void
-ao_telemetry(void)
-{
- uint16_t time;
- int16_t delay;
-
- ao_config_get();
- if (!ao_config.radio_enable)
- ao_exit();
- while (!ao_flight_number)
- ao_sleep(&ao_flight_number);
-
- telemetry.generic.serial = ao_serial_number;
- for (;;) {
- while (ao_telemetry_interval == 0)
- ao_sleep(&telemetry);
- time = ao_rdf_time = ao_time();
- while (ao_telemetry_interval) {
-
-
- ao_send_sensor();
-#if HAS_COMPANION
- if (ao_companion_running)
- ao_send_companion();
-#endif
- ao_send_configuration();
-#if HAS_GPS
- ao_send_location();
- ao_send_satellite();
-#endif
- 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);
- }
- time += ao_telemetry_interval;
- delay = time - ao_time();
- if (delay > 0)
- ao_delay(delay);
- else
- time = ao_time();
- }
- }
-}
-
-void
-ao_telemetry_set_interval(uint16_t interval)
-{
- ao_telemetry_interval = interval;
-
-#if HAS_COMPANION
- if (!ao_companion_setup.update_period)
- ao_companion_setup.update_period = AO_SEC_TO_TICKS(1);
- ao_telemetry_companion_max = ao_companion_setup.update_period / interval;
- ao_telemetry_companion_cur = 1;
-#endif
-
- ao_telemetry_config_max = AO_SEC_TO_TICKS(1) / interval;
-#if HAS_COMPANION
- ao_telemetry_config_cur = ao_telemetry_companion_cur;
- if (ao_telemetry_config_max > ao_telemetry_config_cur)
- ao_telemetry_config_cur++;
-#else
- ao_telemetry_config_cur = 1;
-#endif
-
-#if HAS_GPS
- ao_telemetry_loc_cur = ao_telemetry_config_cur;
- if (ao_telemetry_config_max > ao_telemetry_loc_cur)
- ao_telemetry_loc_cur++;
- ao_telemetry_sat_cur = ao_telemetry_loc_cur;
- if (ao_telemetry_config_max > ao_telemetry_sat_cur)
- ao_telemetry_sat_cur++;
-#endif
- ao_wakeup(&telemetry);
-}
-
-void
-ao_rdf_set(uint8_t rdf)
-{
- ao_rdf = rdf;
- if (rdf == 0)
- ao_radio_rdf_abort();
- else
- ao_rdf_time = ao_time();
-}
-
-__xdata struct ao_task ao_telemetry_task;
-
-void
-ao_telemetry_init()
-{
- ao_add_task(&ao_telemetry_task, ao_telemetry, "telemetry");
-}
+++ /dev/null
-/*
- * 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_pins.h"
-
-void
-main(void)
-{
- /*
- * Reduce the transient on the ignite pins at startup by
- * pulling the pins low as soon as possible at power up
- */
- ao_ignite_set_pins();
-
- ao_clock_init();
-
- /* Turn on the red LED until the system is stable */
- ao_led_init(LEDS_AVAILABLE);
- ao_led_on(AO_LED_RED);
-
- ao_timer_init();
- ao_adc_init();
- ao_cmd_init();
- ao_storage_init();
- ao_flight_init();
- ao_log_init();
- ao_report_init();
- ao_telemetry_init();
- ao_radio_init();
- ao_packet_slave_init(TRUE);
- ao_igniter_init();
- ao_config_init();
- ao_start_scheduler();
-}
+++ /dev/null
-/*
- * 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_pins.h"
-
-void
-main(void)
-{
- ao_clock_init();
-
-
- /* Turn on the red LED until the system is stable */
- ao_led_init(LEDS_AVAILABLE);
- ao_led_on(AO_LED_RED);
-
- ao_timer_init();
- ao_adc_init();
- ao_cmd_init();
- ao_storage_init();
- ao_flight_nano_init();
- ao_log_init();
- ao_report_init();
- ao_telemetry_init();
- ao_radio_init();
- ao_packet_slave_init(TRUE);
- ao_config_init();
- ao_start_scheduler();
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#define AO_NO_ADC_ISR 1
-#include "ao.h"
-
-void
-main(void)
-{
- ao_clock_init();
-
- /* Turn on the red LED until the system is stable */
- ao_led_init(AO_LED_RED|AO_LED_GREEN);
- ao_led_on(AO_LED_RED);
- ao_timer_init();
- ao_beep_init();
- ao_cmd_init();
- ao_usb_init();
- ao_serial_init();
- ao_monitor_init(AO_LED_GREEN, TRUE);
- ao_radio_init();
- ao_config_init();
- ao_start_scheduler();
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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 __xdata blink_0_task;
-struct ao_task __xdata blink_1_task;
-struct ao_task __xdata wakeup_task;
-struct ao_task __xdata beep_task;
-struct ao_task __xdata echo_task;
-
-void delay(int n) __reentrant
-{
- uint8_t j = 0;
- while (--n)
- while (--j)
- ao_yield();
-}
-
-static __xdata uint8_t blink_chan;
-
-void
-blink_0(void)
-{
- uint8_t b = 0;
- for (;;) {
- b = 1 - b;
- if (b)
- ao_led_on(AO_LED_GREEN);
- else
- ao_led_off(AO_LED_GREEN);
- ao_sleep(&blink_chan);
- }
-}
-
-void
-blink_1(void)
-{
- static __xdata struct ao_adc adc;
-
- for (;;) {
- ao_sleep(&ao_adc_head);
- ao_adc_get(&adc);
- if (adc.accel < 15900)
- ao_led_on(AO_LED_RED);
- else
- ao_led_off(AO_LED_RED);
- }
-}
-
-void
-wakeup(void)
-{
- for (;;) {
- ao_delay(AO_MS_TO_TICKS(100));
- ao_wakeup(&blink_chan);
- }
-}
-
-void
-beep(void)
-{
- static __xdata struct ao_adc adc;
-
- for (;;) {
- ao_delay(AO_SEC_TO_TICKS(1));
- ao_adc_get(&adc);
- if (adc.temp > 7400)
- ao_beep_for(AO_BEEP_LOW, AO_MS_TO_TICKS(50));
- }
-}
-
-void
-echo(void)
-{
- char c;
- for (;;) {
- ao_usb_flush();
- c = ao_usb_getchar();
- ao_usb_putchar(c);
- if (c == '\r')
- ao_usb_putchar('\n');
- }
-}
-
-void
-main(void)
-{
- ao_clock_init();
-
-// ao_add_task(&blink_0_task, blink_0);
-// ao_add_task(&blink_1_task, blink_1);
-// ao_add_task(&wakeup_task, wakeup);
-// ao_add_task(&beep_task, beep);
- ao_add_task(&echo_task, echo);
- ao_timer_init();
- ao_adc_init();
- ao_beep_init();
- ao_led_init();
- ao_usb_init();
-
- ao_start_scheduler();
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#define AO_NO_SERIAL_ISR 1
-#define AO_NO_ADC_ISR 1
-#include "ao.h"
-
-void
-main(void)
-{
- ao_clock_init();
-
- /* Turn on the LED until the system is stable */
- ao_led_init(AO_LED_RED);
- ao_led_on(AO_LED_RED);
- ao_timer_init();
- ao_cmd_init();
- ao_usb_init();
- ao_monitor_init(AO_LED_RED, TRUE);
- ao_rssi_init(AO_LED_RED);
- ao_radio_init();
- ao_dbg_init();
- ao_config_init();
- /* Bring up the USB link */
- P1DIR |= 1;
- P1 |= 1;
- ao_start_scheduler();
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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) __critical
-{
- return ao_tick_count;
-}
-
-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_timer_isr(void) __interrupt 9
-{
- ++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)
-{
- /* NOTE: This uses a timer only present on cc1111 architecture. */
-
- /* disable timer 1 */
- T1CTL = 0;
-
- /* set the sample rate */
- T1CC0H = T1_SAMPLE_TIME >> 8;
- T1CC0L = (uint8_t) T1_SAMPLE_TIME;
-
- T1CCTL0 = T1CCTL_MODE_COMPARE;
- T1CCTL1 = 0;
- T1CCTL2 = 0;
-
- /* clear timer value */
- T1CNTL = 0;
-
- /* enable overflow interrupt */
- OVFIM = 1;
- /* enable timer 1 interrupt */
- T1IE = 1;
-
- /* enable timer 1 in module mode, dividing by 8 */
- T1CTL = T1CTL_MODE_MODULO | T1CTL_DIV_8;
-}
-
-/*
- * AltOS always cranks the clock to the max frequency
- */
-void
-ao_clock_init(void)
-{
- /* Switch system clock to crystal oscilator */
- CLKCON = (CLKCON & ~CLKCON_OSC_MASK) | (CLKCON_OSC_XTAL);
-
- while (!(SLEEP & SLEEP_XOSC_STB))
- ;
-
- /* Crank up the timer tick and system clock speed */
- CLKCON = ((CLKCON & ~(CLKCON_TICKSPD_MASK | CLKCON_CLKSPD_MASK)) |
- (CLKCON_TICKSPD_1 | CLKCON_CLKSPD_1));
-
- while ((CLKCON & (CLKCON_TICKSPD_MASK|CLKCON_CLKSPD_MASK)) !=
- (CLKCON_TICKSPD_1 | CLKCON_CLKSPD_1))
- ;
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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"
-
-struct ao_task __xdata ao_usb_task;
-
-static __xdata uint16_t ao_usb_in_bytes;
-static __pdata uint16_t ao_usb_in_bytes_last;
-static __xdata uint16_t ao_usb_out_bytes;
-static __pdata uint8_t ao_usb_iif;
-static __pdata uint8_t ao_usb_running;
-
-static void
-ao_usb_set_interrupts(void)
-{
- /* IN interrupts on the control an IN endpoints */
- USBIIE = (1 << AO_USB_CONTROL_EP) | (1 << AO_USB_IN_EP);
-
- /* OUT interrupts on the OUT endpoint */
- USBOIE = (1 << AO_USB_OUT_EP);
-
- /* Only care about reset */
- USBCIE = USBCIE_RSTIE;
-}
-
-/* This interrupt is shared with port 2,
- * so when we hook that up, fix this
- */
-void
-ao_usb_isr(void) __interrupt 6
-{
- USBIF = 0;
- ao_usb_iif |= USBIIF;
- if (ao_usb_iif & 1)
- ao_wakeup(&ao_usb_task);
- if (ao_usb_iif & (1 << AO_USB_IN_EP))
- ao_wakeup(&ao_usb_in_bytes);
-
- if (USBOIF & (1 << AO_USB_OUT_EP))
- ao_wakeup(&ao_stdin_ready);
-
- if (USBCIF & USBCIF_RSTIF)
- ao_usb_set_interrupts();
-#if HAS_BTM
-#if BT_LINK_ON_P2
- ao_btm_isr();
-#endif
-#endif
-}
-
-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;
-
-__pdata uint8_t ao_usb_ep0_state;
-uint8_t * __pdata ao_usb_ep0_in_data;
-__pdata uint8_t ao_usb_ep0_in_len;
-__pdata uint8_t ao_usb_ep0_in_buf[2];
-__pdata uint8_t ao_usb_ep0_out_len;
-__xdata uint8_t *__pdata ao_usb_ep0_out_data;
-__pdata uint8_t ao_usb_configuration;
-
-/* Send an IN data packet */
-static void
-ao_usb_ep0_flush(void)
-{
- __pdata uint8_t this_len;
- __pdata uint8_t cs0;
-
- /* If the IN packet hasn't been picked up, just return */
- USBINDEX = 0;
- cs0 = USBCS0;
- if (cs0 & USBCS0_INPKT_RDY)
- return;
-
- this_len = ao_usb_ep0_in_len;
- if (this_len > AO_USB_CONTROL_SIZE)
- this_len = AO_USB_CONTROL_SIZE;
- cs0 = USBCS0_INPKT_RDY;
- if (this_len != AO_USB_CONTROL_SIZE) {
- cs0 = USBCS0_INPKT_RDY | USBCS0_DATA_END;
- ao_usb_ep0_state = AO_USB_EP0_IDLE;
- }
- ao_usb_ep0_in_len -= this_len;
- while (this_len--)
- USBFIFO[0] = *ao_usb_ep0_in_data++;
- USBINDEX = 0;
- USBCS0 = cs0;
-}
-
-__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)
-{
- __code uint8_t *__pdata descriptor;
- __pdata uint8_t type = value >> 8;
- __pdata 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];
- }
-}
-
-/* Read data from the ep0 OUT fifo
- */
-static void
-ao_usb_ep0_fill(void)
-{
- __pdata uint8_t len;
-
- USBINDEX = 0;
- len = USBCNT0;
- if (len > ao_usb_ep0_out_len)
- len = ao_usb_ep0_out_len;
- ao_usb_ep0_out_len -= len;
- while (len--)
- *ao_usb_ep0_out_data++ = USBFIFO[0];
-}
-
-void
-ao_usb_ep0_queue_byte(uint8_t a)
-{
- ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a;
-}
-
-void
-ao_usb_set_address(uint8_t address)
-{
- ao_usb_running = 1;
- USBADDR = address | 0x80;
- while (USBADDR & 0x80)
- ;
-}
-
-static void
-ao_usb_set_configuration(void)
-{
- /* Set the IN max packet size, double buffered */
- USBINDEX = AO_USB_IN_EP;
- USBMAXI = AO_USB_IN_SIZE >> 3;
- USBCSIH |= USBCSIH_IN_DBL_BUF;
-
- /* Set the OUT max packet size, double buffered */
- USBINDEX = AO_USB_OUT_EP;
- USBMAXO = AO_USB_OUT_SIZE >> 3;
- USBCSOH = USBCSOH_OUT_DBL_BUF;
-}
-
-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();
- if (ao_usb_ep0_out_len != 0)
- 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;
- }
- USBINDEX = 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:
- switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) {
- case AO_USB_RECIP_DEVICE:
- 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_SET_ADDRESS:
- ao_usb_set_address(ao_usb_setup.value);
- break;
- case AO_USB_REQ_GET_DESCRIPTOR:
- ao_usb_get_descriptor(ao_usb_setup.value);
- break;
- case AO_USB_REQ_GET_CONFIGURATION:
- ao_usb_ep0_queue_byte(ao_usb_configuration);
- break;
- case AO_USB_REQ_SET_CONFIGURATION:
- ao_usb_configuration = ao_usb_setup.value;
- ao_usb_set_configuration();
- break;
- }
- break;
- case AO_USB_RECIP_INTERFACE:
- #pragma disable_warning 110
- 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:
- 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:
- switch (ao_usb_setup.request) {
- case SET_LINE_CODING:
- ao_usb_ep0_out_len = 7;
- ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_line_coding;
- break;
- case GET_LINE_CODING:
- 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;
- ao_usb_ep0_flush();
- }
-}
-
-/* End point 0 receives all of the control messages. */
-static void
-ao_usb_ep0(void)
-{
- __pdata uint8_t cs0;
-
- ao_usb_ep0_state = AO_USB_EP0_IDLE;
- for (;;) {
- __critical for (;;) {
- if (ao_usb_iif & 1) {
- ao_usb_iif &= ~1;
- break;
- }
- ao_sleep(&ao_usb_task);
- }
- USBINDEX = 0;
- cs0 = USBCS0;
- if (cs0 & USBCS0_SETUP_END) {
- ao_usb_ep0_state = AO_USB_EP0_IDLE;
- USBCS0 = USBCS0_CLR_SETUP_END;
- }
- if (cs0 & USBCS0_SENT_STALL) {
- ao_usb_ep0_state = AO_USB_EP0_IDLE;
- USBCS0 &= ~USBCS0_SENT_STALL;
- }
- if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN &&
- (cs0 & USBCS0_INPKT_RDY) == 0)
- {
- ao_usb_ep0_flush();
- }
- if (cs0 & USBCS0_OUTPKT_RDY) {
- switch (ao_usb_ep0_state) {
- case AO_USB_EP0_IDLE:
- ao_usb_ep0_setup();
- break;
- case AO_USB_EP0_DATA_OUT:
- ao_usb_ep0_fill();
- if (ao_usb_ep0_out_len == 0)
- ao_usb_ep0_state = AO_USB_EP0_IDLE;
- USBINDEX = 0;
- if (ao_usb_ep0_state == AO_USB_EP0_IDLE)
- USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END;
- else
- USBCS0 = USBCS0_CLR_OUTPKT_RDY;
- break;
- }
- }
- }
-}
-
-/* Wait for a free IN buffer */
-static void
-ao_usb_in_wait(void)
-{
- for (;;) {
- USBINDEX = AO_USB_IN_EP;
- if ((USBCSIL & USBCSIL_INPKT_RDY) == 0)
- break;
- ao_sleep(&ao_usb_in_bytes);
- }
-}
-
-/* Send the current IN packet */
-static void
-ao_usb_in_send(void)
-{
- USBINDEX = AO_USB_IN_EP;
- USBCSIL |= USBCSIL_INPKT_RDY;
- ao_usb_in_bytes_last = ao_usb_in_bytes;
- ao_usb_in_bytes = 0;
-}
-
-void
-ao_usb_flush(void) __critical
-{
- if (!ao_usb_running)
- return;
-
- /* If there are pending bytes, or if the last packet was full,
- * send another IN packet
- */
- if (ao_usb_in_bytes || (ao_usb_in_bytes_last == AO_USB_IN_SIZE)) {
- 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, sending the packet when full */
- USBFIFO[AO_USB_IN_EP << 1] = c;
- if (++ao_usb_in_bytes == AO_USB_IN_SIZE)
- ao_usb_in_send();
-}
-
-char
-ao_usb_pollchar(void) __critical
-{
- char c;
- if (ao_usb_out_bytes == 0) {
- USBINDEX = AO_USB_OUT_EP;
- if ((USBCSOL & USBCSOL_OUTPKT_RDY) == 0)
- return AO_READ_AGAIN;
- ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL;
- if (ao_usb_out_bytes == 0) {
- USBINDEX = AO_USB_OUT_EP;
- USBCSOL &= ~USBCSOL_OUTPKT_RDY;
- return AO_READ_AGAIN;
- }
- }
- --ao_usb_out_bytes;
- c = USBFIFO[AO_USB_OUT_EP << 1];
- if (ao_usb_out_bytes == 0) {
- USBINDEX = AO_USB_OUT_EP;
- USBCSOL &= ~USBCSOL_OUTPKT_RDY;
- }
- return c;
-}
-
-char
-ao_usb_getchar(void) __critical
-{
- char c;
-
- while ((c = ao_usb_pollchar()) == AO_READ_AGAIN)
- ao_sleep(&ao_stdin_ready);
- return c;
-}
-
-void
-ao_usb_enable(void)
-{
- /* Turn on the USB controller */
- SLEEP |= SLEEP_USB_EN;
-
- ao_usb_set_configuration();
-
- ao_usb_set_interrupts();
-
- /* enable USB interrupts */
- IEN2 |= IEN2_USBIE;
-
- /* Clear any pending interrupts */
- USBCIF = 0;
- USBOIF = 0;
- USBIIF = 0;
-}
-
-void
-ao_usb_disable(void)
-{
- /* Disable USB interrupts */
- USBIIE = 0;
- USBOIE = 0;
- USBCIE = 0;
- IEN2 &= ~IEN2_USBIE;
-
- /* Clear any pending interrupts */
- USBCIF = 0;
- USBOIF = 0;
- USBIIF = 0;
-
- /* Turn off the USB controller */
- SLEEP &= ~SLEEP_USB_EN;
-}
-
-void
-ao_usb_init(void)
-{
- ao_usb_enable();
-
- ao_add_task(&ao_usb_task, ao_usb_ep0, "usb");
- ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush);
-}
+++ /dev/null
-/*
- * Copyright © 2009 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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_ */
+++ /dev/null
-/*
- * 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.
- */
-
-/* Defines for the Atmel AT45DB161D 16Mbit SPI Bus DataFlash® */
-
-#ifndef _AT45DB161D_H_
-#define _AT45DB161D_H_
-
-/*
- * We reserve the last block on the device for
- * configuration space. Writes and reads in this
- * area return errors.
- */
-
-
-#define FLASH_READ 0x03
-#define FLASH_WRITE 0x82
-#define FLASH_PAGE_ERASE 0x81
-#define FLASH_READ_STATUS 0xd7
-#define FLASH_SET_CONFIG 0x3d
-
-#define FLASH_SET_512_BYTE_0 0x2a
-#define FLASH_SET_512_BYTE_1 0x80
-#define FLASH_SET_512_BYTE_2 0xa6
-
-#define FLASH_STATUS_RDY (1 << 7)
-#define FLASH_STATUS_COMP (1 << 6)
-#define FLASH_STATUS_PROTECT (1 << 1)
-#define FLASH_STATUS_PAGESIZE_512 (1 << 0)
-
-#endif /* _AT45DB161D_H_ */
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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]);
+}
--- /dev/null
+/*
+ * 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_ */
+
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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");
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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;
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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"
+
+const uint16_t ao_serial_number = 0;
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+ * 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 */
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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 */
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_ */
--- /dev/null
+/*
+ * 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);
+}
+++ /dev/null
-/*-------------------------------------------------------------------------
- Register Declarations for the ChipCon CC1111 Processor Range
-
- Copyright © 2008 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.
-
- Adapted from the Cygnal C8051F12x config file which is:
-
- Copyright (C) 2003 - Maarten Brock, sourceforge.brock@dse.nl
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--------------------------------------------------------------------------*/
-
-#ifndef _CC1111_H_
-#define _CC1111_H_
-#include <cc1110.h>
-#include <stdint.h>
-
-__sfr __at 0xA8 IEN0; /* Interrupt Enable 0 Register */
-
-sbit __at 0xA8 RFTXRXIE; /* RF TX/RX done interrupt enable */
-sbit __at 0xA9 ADCIE; /* ADC interrupt enable */
-sbit __at 0xAA URX0IE; /* USART0 RX interrupt enable */
-sbit __at 0xAB URX1IE; /* USART1 RX interrupt enable (shared with I2S RX) */
-sbit __at 0xAB I2SRXIE; /* I2S RX interrupt enable (shared with USART1 RX) */
-sbit __at 0xAC ENCIE; /* AES encryption/decryption interrupt enable */
-sbit __at 0xAD STIE; /* Sleep Timer interrupt enable */
-sbit __at 0xAF EA; /* Enable All */
-
-#define IEN0_EA (1 << 7)
-#define IEN0_STIE (1 << 5)
-#define IEN0_ENCIE (1 << 4)
-#define IEN0_URX1IE (1 << 3)
-#define IEN0_I2SRXIE (1 << 3)
-#define IEN0_URX0IE (1 << 2)
-#define IEN0_ADCIE (1 << 1)
-#define IEN0_RFTXRXIE (1 << 0)
-
-__sfr __at 0xB8 IEN1; /* Interrupt Enable 1 Register */
-
-#define IEN1_P0IE (1 << 5) /* Port 0 interrupt enable */
-#define IEN1_T4IE (1 << 4) /* Timer 4 interrupt enable */
-#define IEN1_T3IE (1 << 3) /* Timer 3 interrupt enable */
-#define IEN1_T2IE (1 << 2) /* Timer 2 interrupt enable */
-#define IEN1_T1IE (1 << 1) /* Timer 1 interrupt enable */
-#define IEN1_DMAIE (1 << 0) /* DMA transfer interrupt enable */
-
-/* IEN2 */
-__sfr __at 0x9A IEN2; /* Interrupt Enable 2 Register */
-
-#define IEN2_WDTIE (1 << 5) /* Watchdog timer interrupt enable */
-#define IEN2_P1IE (1 << 4) /* Port 1 interrupt enable */
-#define IEN2_UTX1IE (1 << 3) /* USART1 TX interrupt enable */
-#define IEN2_I2STXIE (1 << 3) /* I2S TX interrupt enable */
-#define IEN2_UTX0IE (1 << 2) /* USART0 TX interrupt enable */
-#define IEN2_P2IE (1 << 1) /* Port 2 interrupt enable */
-#define IEN2_USBIE (1 << 1) /* USB interrupt enable */
-#define IEN2_RFIE (1 << 0) /* RF general interrupt enable */
-
-/* CLKCON 0xC6 */
-__sfr __at 0xC6 CLKCON; /* Clock Control */
-
-#define CLKCON_OSC32K_RC (1 << 7)
-#define CLKCON_OSC32K_XTAL (0 << 7)
-#define CLKCON_OSC32K_MASK (1 << 7)
-#define CLKCON_OSC_RC (1 << 6)
-#define CLKCON_OSC_XTAL (0 << 6)
-#define CLKCON_OSC_MASK (1 << 6)
-#define CLKCON_TICKSPD_MASK (7 << 3)
-# define CLKCON_TICKSPD_1 (0 << 3)
-# define CLKCON_TICKSPD_1_2 (1 << 3)
-# define CLKCON_TICKSPD_1_4 (2 << 3)
-# define CLKCON_TICKSPD_1_8 (3 << 3)
-# define CLKCON_TICKSPD_1_16 (4 << 3)
-# define CLKCON_TICKSPD_1_32 (5 << 3)
-# define CLKCON_TICKSPD_1_64 (6 << 3)
-# define CLKCON_TICKSPD_1_128 (7 << 3)
-
-#define CLKCON_CLKSPD_MASK (7 << 0)
-# define CLKCON_CLKSPD_1 (0 << 0)
-# define CLKCON_CLKSPD_1_2 (1 << 0)
-# define CLKCON_CLKSPD_1_4 (2 << 0)
-# define CLKCON_CLKSPD_1_8 (3 << 0)
-# define CLKCON_CLKSPD_1_16 (4 << 0)
-# define CLKCON_CLKSPD_1_32 (5 << 0)
-# define CLKCON_CLKSPD_1_64 (6 << 0)
-# define CLKCON_CLKSPD_1_128 (7 << 0)
-
-/* SLEEP 0xBE */
-#define SLEEP_USB_EN (1 << 7)
-#define SLEEP_XOSC_STB (1 << 6)
-#define SLEEP_HFRC_STB (1 << 5)
-#define SLEEP_RST_POWER (0 << 3)
-#define SLEEP_RST_EXTERNAL (1 << 3)
-#define SLEEP_RST_WATCHDOG (2 << 3)
-#define SLEEP_RST_MASK (3 << 3)
-#define SLEEP_OSC_PD (1 << 2)
-#define SLEEP_MODE_PM0 (0 << 0)
-#define SLEEP_MODE_PM1 (1 << 0)
-#define SLEEP_MODE_PM2 (2 << 0)
-#define SLEEP_MODE_PM3 (3 << 0)
-#define SLEEP_MODE_MASK (3 << 0)
-
-/* PCON 0x87 */
-__sfr __at 0x87 PCON; /* Power Mode Control Register */
-
-#define PCON_IDLE (1 << 0)
-
-/*
- * TCON
- */
-__sfr __at 0x88 TCON; /* CPU Interrupt Flag 1 */
-
-sbit __at 0x8F URX1IF; /* USART1 RX interrupt flag. Automatically cleared */
-sbit __at 0x8F I2SRXIF; /* I2S RX interrupt flag. Automatically cleared */
-sbit __at 0x8D ADCIF; /* ADC interrupt flag. Automatically cleared */
-sbit __at 0x8B URX0IF; /* USART0 RX interrupt flag. Automatically cleared */
-sbit __at 0x89 RFTXRXIF; /* RF TX/RX complete interrupt flag. Automatically cleared */
-
-#define TCON_URX1IF (1 << 7)
-#define TCON_I2SRXIF (1 << 7)
-#define TCON_ADCIF (1 << 5)
-#define TCON_URX0IF (1 << 3)
-#define TCON_RFTXRXIF (1 << 1)
-
-/*
- * S0CON
- */
-__sfr __at 0x98 S0CON; /* CPU Interrupt Flag 2 */
-
-sbit __at 0x98 ENCIF_0; /* AES interrupt 0. */
-sbit __at 0x99 ENCIF_1; /* AES interrupt 1. */
-
-#define S0CON_ENCIF_1 (1 << 1)
-#define S0CON_ENCIF_0 (1 << 0)
-
-/*
- * S1CON
- */
-__sfr __at 0x9B S1CON; /* CPU Interrupt Flag 3 */
-
-#define S1CON_RFIF_1 (1 << 1)
-#define S1CON_RFIF_0 (1 << 0)
-
-/*
- * IRCON
- */
-__sfr __at 0xC0 IRCON; /* CPU Interrupt Flag 4 */
-
-sbit __at 0xC0 DMAIF; /* DMA complete interrupt flag */
-sbit __at 0xC1 T1IF; /* Timer 1 interrupt flag. Automatically cleared */
-sbit __at 0xC2 T2IF; /* Timer 2 interrupt flag. Automatically cleared */
-sbit __at 0xC3 T3IF; /* Timer 3 interrupt flag. Automatically cleared */
-sbit __at 0xC4 T4IF; /* Timer 4 interrupt flag. Automatically cleared */
-sbit __at 0xC5 P0IF; /* Port0 interrupt flag */
-sbit __at 0xC7 STIF; /* Sleep Timer interrupt flag */
-
-#define IRCON_DMAIF (1 << 0) /* DMA complete interrupt flag */
-#define IRCON_T1IF (1 << 1) /* Timer 1 interrupt flag. Automatically cleared */
-#define IRCON_T2IF (1 << 2) /* Timer 2 interrupt flag. Automatically cleared */
-#define IRCON_T3IF (1 << 3) /* Timer 3 interrupt flag. Automatically cleared */
-#define IRCON_T4IF (1 << 4) /* Timer 4 interrupt flag. Automatically cleared */
-#define IRCON_P0IF (1 << 5) /* Port0 interrupt flag */
-#define IRCON_STIF (1 << 7) /* Sleep Timer interrupt flag */
-
-/*
- * IRCON2
- */
-__sfr __at 0xE8 IRCON2; /* CPU Interrupt Flag 5 */
-
-sbit __at 0xE8 USBIF; /* USB interrupt flag (shared with Port2) */
-sbit __at 0xE8 P2IF; /* Port2 interrupt flag (shared with USB) */
-sbit __at 0xE9 UTX0IF; /* USART0 TX interrupt flag */
-sbit __at 0xEA UTX1IF; /* USART1 TX interrupt flag (shared with I2S TX) */
-sbit __at 0xEA I2STXIF; /* I2S TX interrupt flag (shared with USART1 TX) */
-sbit __at 0xEB P1IF; /* Port1 interrupt flag */
-sbit __at 0xEC WDTIF; /* Watchdog timer interrupt flag */
-
-#define IRCON2_USBIF (1 << 0) /* USB interrupt flag (shared with Port2) */
-#define IRCON2_P2IF (1 << 0) /* Port2 interrupt flag (shared with USB) */
-#define IRCON2_UTX0IF (1 << 1) /* USART0 TX interrupt flag */
-#define IRCON2_UTX1IF (1 << 2) /* USART1 TX interrupt flag (shared with I2S TX) */
-#define IRCON2_I2STXIF (1 << 2) /* I2S TX interrupt flag (shared with USART1 TX) */
-#define IRCON2_P1IF (1 << 3) /* Port1 interrupt flag */
-#define IRCON2_WDTIF (1 << 4) /* Watchdog timer interrupt flag */
-
-/*
- * IP1 - Interrupt Priority 1
- */
-
-/*
- * Interrupt priority groups:
- *
- * IPG0 RFTXRX RF DMA
- * IPG1 ADC T1 P2INT/USB
- * IPG2 URX0 T2 UTX0
- * IPG3 URX1/I2SRX T3 UTX1 / I2STX
- * IPG4 ENC T4 P1INT
- * IPG5 ST P0INT WDT
- *
- * Priority = (IP1 << 1) | IP0. Higher priority interrupts served first
- */
-
-__sfr __at 0xB9 IP1; /* Interrupt Priority 1 */
-__sfr __at 0xA9 IP0; /* Interrupt Priority 0 */
-
-#define IP1_IPG5 (1 << 5)
-#define IP1_IPG4 (1 << 4)
-#define IP1_IPG3 (1 << 3)
-#define IP1_IPG2 (1 << 2)
-#define IP1_IPG1 (1 << 1)
-#define IP1_IPG0 (1 << 0)
-
-#define IP0_IPG5 (1 << 5)
-#define IP0_IPG4 (1 << 4)
-#define IP0_IPG3 (1 << 3)
-#define IP0_IPG2 (1 << 2)
-#define IP0_IPG1 (1 << 1)
-#define IP0_IPG0 (1 << 0)
-
-/*
- * Timer 1
- */
-#define T1CTL_MODE_SUSPENDED (0 << 0)
-#define T1CTL_MODE_FREE (1 << 0)
-#define T1CTL_MODE_MODULO (2 << 0)
-#define T1CTL_MODE_UP_DOWN (3 << 0)
-#define T1CTL_MODE_MASK (3 << 0)
-#define T1CTL_DIV_1 (0 << 2)
-#define T1CTL_DIV_8 (1 << 2)
-#define T1CTL_DIV_32 (2 << 2)
-#define T1CTL_DIV_128 (3 << 2)
-#define T1CTL_DIV_MASK (3 << 2)
-#define T1CTL_OVFIF (1 << 4)
-#define T1CTL_CH0IF (1 << 5)
-#define T1CTL_CH1IF (1 << 6)
-#define T1CTL_CH2IF (1 << 7)
-
-#define T1CCTL_NO_CAPTURE (0 << 0)
-#define T1CCTL_CAPTURE_RISING (1 << 0)
-#define T1CCTL_CAPTURE_FALLING (2 << 0)
-#define T1CCTL_CAPTURE_BOTH (3 << 0)
-#define T1CCTL_CAPTURE_MASK (3 << 0)
-
-#define T1CCTL_MODE_CAPTURE (0 << 2)
-#define T1CCTL_MODE_COMPARE (1 << 2)
-
-#define T1CTL_CMP_SET (0 << 3)
-#define T1CTL_CMP_CLEAR (1 << 3)
-#define T1CTL_CMP_TOGGLE (2 << 3)
-#define T1CTL_CMP_SET_CLEAR (3 << 3)
-#define T1CTL_CMP_CLEAR_SET (4 << 3)
-
-#define T1CTL_IM_DISABLED (0 << 6)
-#define T1CTL_IM_ENABLED (1 << 6)
-
-#define T1CTL_CPSEL_NORMAL (0 << 7)
-#define T1CTL_CPSEL_RF (1 << 7)
-
-/*
- * Timer 3 and Timer 4
- */
-
-/* Timer count */
-__sfr __at 0xCA T3CNT;
-__sfr __at 0xEA T4CNT;
-
-/* Timer control */
-
-__sfr __at 0xCB T3CTL;
-__sfr __at 0xEB T4CTL;
-
-#define TxCTL_DIV_1 (0 << 5)
-#define TxCTL_DIV_2 (1 << 5)
-#define TxCTL_DIV_4 (2 << 5)
-#define TxCTL_DIV_8 (3 << 5)
-#define TxCTL_DIV_16 (4 << 5)
-#define TxCTL_DIV_32 (5 << 5)
-#define TxCTL_DIV_64 (6 << 5)
-#define TxCTL_DIV_128 (7 << 5)
-#define TxCTL_START (1 << 4)
-#define TxCTL_OVFIM (1 << 3)
-#define TxCTL_CLR (1 << 2)
-#define TxCTL_MODE_FREE (0 << 0)
-#define TxCTL_MODE_DOWN (1 << 0)
-#define TxCTL_MODE_MODULO (2 << 0)
-#define TxCTL_MODE_UP_DOWN (3 << 0)
-
-/* Timer 4 channel 0 compare control */
-
-__sfr __at 0xCC T3CCTL0;
-__sfr __at 0xCE T3CCTL1;
-__sfr __at 0xEC T4CCTL0;
-__sfr __at 0xEE T4CCTL1;
-
-#define TxCCTLy_IM (1 << 6)
-#define TxCCTLy_CMP_SET (0 << 3)
-#define TxCCTLy_CMP_CLEAR (1 << 3)
-#define TxCCTLy_CMP_TOGGLE (2 << 3)
-#define TxCCTLy_CMP_SET_UP_CLEAR_DOWN (3 << 3)
-#define TxCCTLy_CMP_CLEAR_UP_SET_DOWN (4 << 3)
-#define TxCCTLy_CMP_SET_CLEAR_FF (5 << 3)
-#define TxCCTLy_CMP_CLEAR_SET_00 (6 << 3)
-#define TxCCTLy_CMP_MODE_ENABLE (1 << 2)
-
-/* Timer compare value */
-__sfr __at 0xCD T3CC0;
-__sfr __at 0xCF T3CC1;
-__sfr __at 0xED T4CC0;
-__sfr __at 0xEF T4CC1;
-
-/*
- * Peripheral control
- */
-
-__sfr __at 0xf1 PERCFG;
-#define PERCFG_T1CFG_ALT_1 (0 << 6)
-#define PERCFG_T1CFG_ALT_2 (1 << 6)
-#define PERCFG_T1CFG_ALT_MASK (1 << 6)
-
-#define PERCFG_T3CFG_ALT_1 (0 << 5)
-#define PERCFG_T3CFG_ALT_2 (1 << 5)
-#define PERCFG_T3CFG_ALT_MASK (1 << 5)
-
-#define PERCFG_T4CFG_ALT_1 (0 << 4)
-#define PERCFG_T4CFG_ALT_2 (1 << 4)
-#define PERCFG_T4CFG_ALT_MASK (1 << 4)
-
-#define PERCFG_U1CFG_ALT_1 (0 << 1)
-#define PERCFG_U1CFG_ALT_2 (1 << 1)
-#define PERCFG_U1CFG_ALT_MASK (1 << 1)
-
-#define PERCFG_U0CFG_ALT_1 (0 << 0)
-#define PERCFG_U0CFG_ALT_2 (1 << 0)
-#define PERCFG_U0CFG_ALT_MASK (1 << 0)
-
-/* directly addressed USB registers */
-__xdata __at (0xde00) volatile uint8_t USBADDR;
-__xdata __at (0xde01) volatile uint8_t USBPOW;
-__xdata __at (0xde02) volatile uint8_t USBIIF;
-
-__xdata __at (0xde04) volatile uint8_t USBOIF;
-
-__xdata __at (0xde06) volatile uint8_t USBCIF;
-
-# define USBCIF_SOFIF (1 << 3)
-# define USBCIF_RSTIF (1 << 2)
-# define USBCIF_RESUMEIF (1 << 1)
-# define USBCIF_SUSPENDIF (1 << 0)
-
-__xdata __at (0xde07) volatile uint8_t USBIIE;
-
-__xdata __at (0xde09) volatile uint8_t USBOIE;
-
-__xdata __at (0xde0b) volatile uint8_t USBCIE;
-
-# define USBCIE_SOFIE (1 << 3)
-# define USBCIE_RSTIE (1 << 2)
-# define USBCIE_RESUMEIE (1 << 1)
-# define USBCIE_SUSPENDIE (1 << 0)
-
-__xdata __at (0xde0c) volatile uint8_t USBFRML;
-__xdata __at (0xde0d) volatile uint8_t USBFRMH;
-__xdata __at (0xde0e) volatile uint8_t USBINDEX;
-
-/* indexed USB registers, must set USBINDEX to 0-5 */
-__xdata __at (0xde10) volatile uint8_t USBMAXI;
-__xdata __at (0xde11) volatile uint8_t USBCS0;
-
-# define USBCS0_CLR_SETUP_END (1 << 7)
-# define USBCS0_CLR_OUTPKT_RDY (1 << 6)
-# define USBCS0_SEND_STALL (1 << 5)
-# define USBCS0_SETUP_END (1 << 4)
-# define USBCS0_DATA_END (1 << 3)
-# define USBCS0_SENT_STALL (1 << 2)
-# define USBCS0_INPKT_RDY (1 << 1)
-# define USBCS0_OUTPKT_RDY (1 << 0)
-
-__xdata __at (0xde11) volatile uint8_t USBCSIL;
-
-# define USBCSIL_CLR_DATA_TOG (1 << 6)
-# define USBCSIL_SENT_STALL (1 << 5)
-# define USBCSIL_SEND_STALL (1 << 4)
-# define USBCSIL_FLUSH_PACKET (1 << 3)
-# define USBCSIL_UNDERRUN (1 << 2)
-# define USBCSIL_PKT_PRESENT (1 << 1)
-# define USBCSIL_INPKT_RDY (1 << 0)
-
-__xdata __at (0xde12) volatile uint8_t USBCSIH;
-
-# define USBCSIH_AUTOSET (1 << 7)
-# define USBCSIH_ISO (1 << 6)
-# define USBCSIH_FORCE_DATA_TOG (1 << 3)
-# define USBCSIH_IN_DBL_BUF (1 << 0)
-
-__xdata __at (0xde13) volatile uint8_t USBMAXO;
-__xdata __at (0xde14) volatile uint8_t USBCSOL;
-
-# define USBCSOL_CLR_DATA_TOG (1 << 7)
-# define USBCSOL_SENT_STALL (1 << 6)
-# define USBCSOL_SEND_STALL (1 << 5)
-# define USBCSOL_FLUSH_PACKET (1 << 4)
-# define USBCSOL_DATA_ERROR (1 << 3)
-# define USBCSOL_OVERRUN (1 << 2)
-# define USBCSOL_FIFO_FULL (1 << 1)
-# define USBCSOL_OUTPKT_RDY (1 << 0)
-
-__xdata __at (0xde15) volatile uint8_t USBCSOH;
-
-# define USBCSOH_AUTOCLEAR (1 << 7)
-# define USBCSOH_ISO (1 << 6)
-# define USBCSOH_OUT_DBL_BUF (1 << 0)
-
-__xdata __at (0xde16) volatile uint8_t USBCNT0;
-__xdata __at (0xde16) volatile uint8_t USBCNTL;
-__xdata __at (0xde17) volatile uint8_t USBCNTH;
-
-__xdata __at (0xde20) volatile uint8_t USBFIFO[12];
-
-/* ADC Data register, low and high */
-__sfr at 0xBA ADCL;
-__sfr at 0xBB ADCH;
-__xdata __at (0xDFBA) volatile uint16_t ADCXDATA;
-
-/* ADC Control Register 1 */
-__sfr at 0xB4 ADCCON1;
-
-# define ADCCON1_EOC (1 << 7) /* conversion complete */
-# define ADCCON1_ST (1 << 6) /* start conversion */
-
-# define ADCCON1_STSEL_MASK (3 << 4) /* start select */
-# define ADCCON1_STSEL_EXTERNAL (0 << 4) /* P2_0 pin triggers */
-# define ADCCON1_STSEL_FULLSPEED (1 << 4) /* full speed, no waiting */
-# define ADCCON1_STSEL_TIMER1 (2 << 4) /* timer 1 channel 0 */
-# define ADCCON1_STSEL_START (3 << 4) /* set start bit */
-
-# define ADCCON1_RCTRL_MASK (3 << 2) /* random number control */
-# define ADCCON1_RCTRL_COMPLETE (0 << 2) /* operation completed */
-# define ADCCON1_RCTRL_CLOCK_LFSR (1 << 2) /* Clock the LFSR once */
-
-/* ADC Control Register 2 */
-__sfr at 0xB5 ADCCON2;
-
-# define ADCCON2_SREF_MASK (3 << 6) /* reference voltage */
-# define ADCCON2_SREF_1_25V (0 << 6) /* internal 1.25V */
-# define ADCCON2_SREF_EXTERNAL (1 << 6) /* external on AIN7 cc1110 */
-# define ADCCON2_SREF_VDD (2 << 6) /* VDD on the AVDD pin */
-# define ADCCON2_SREF_EXTERNAL_DIFF (3 << 6) /* external on AIN6-7 cc1110 */
-
-# define ADCCON2_SDIV_MASK (3 << 4) /* decimation rate */
-# define ADCCON2_SDIV_64 (0 << 4) /* 7 bits */
-# define ADCCON2_SDIV_128 (1 << 4) /* 9 bits */
-# define ADCCON2_SDIV_256 (2 << 4) /* 10 bits */
-# define ADCCON2_SDIV_512 (3 << 4) /* 12 bits */
-
-# define ADCCON2_SCH_MASK (0xf << 0) /* Sequence channel select */
-# define ADCCON2_SCH_SHIFT 0
-# define ADCCON2_SCH_AIN0 (0 << 0)
-# define ADCCON2_SCH_AIN1 (1 << 0)
-# define ADCCON2_SCH_AIN2 (2 << 0)
-# define ADCCON2_SCH_AIN3 (3 << 0)
-# define ADCCON2_SCH_AIN4 (4 << 0)
-# define ADCCON2_SCH_AIN5 (5 << 0)
-# define ADCCON2_SCH_AIN6 (6 << 0)
-# define ADCCON2_SCH_AIN7 (7 << 0)
-# define ADCCON2_SCH_AIN0_AIN1 (8 << 0)
-# define ADCCON2_SCH_AIN2_AIN3 (9 << 0)
-# define ADCCON2_SCH_AIN4_AIN5 (0xa << 0)
-# define ADCCON2_SCH_AIN6_AIN7 (0xb << 0)
-# define ADCCON2_SCH_GND (0xc << 0)
-# define ADCCON2_SCH_VREF (0xd << 0)
-# define ADCCON2_SCH_TEMP (0xe << 0)
-# define ADCCON2_SCH_VDD_3 (0xf << 0)
-
-
-/* ADC Control Register 3 */
-__sfr at 0xB6 ADCCON3;
-
-# define ADCCON3_EREF_MASK (3 << 6) /* extra conversion reference */
-# define ADCCON3_EREF_1_25 (0 << 6) /* internal 1.25V */
-# define ADCCON3_EREF_EXTERNAL (1 << 6) /* external AIN7 cc1110 */
-# define ADCCON3_EREF_VDD (2 << 6) /* VDD on the AVDD pin */
-# define ADCCON3_EREF_EXTERNAL_DIFF (3 << 6) /* external AIN6-7 cc1110 */
-# define ADCCON3_EDIV_MASK (3 << 4) /* extral decimation */
-# define ADCCON3_EDIV_64 (0 << 4) /* 7 bits */
-# define ADCCON3_EDIV_128 (1 << 4) /* 9 bits */
-# define ADCCON3_EDIV_256 (2 << 4) /* 10 bits */
-# define ADCCON3_EDIV_512 (3 << 4) /* 12 bits */
-# define ADCCON3_ECH_MASK (0xf << 0) /* Sequence channel select */
-# define ADCCON3_ECH_SHIFT 0
-# define ADCCON3_ECH_AIN0 (0 << 0)
-# define ADCCON3_ECH_AIN1 (1 << 0)
-# define ADCCON3_ECH_AIN2 (2 << 0)
-# define ADCCON3_ECH_AIN3 (3 << 0)
-# define ADCCON3_ECH_AIN4 (4 << 0)
-# define ADCCON3_ECH_AIN5 (5 << 0)
-# define ADCCON3_ECH_AIN6 (6 << 0)
-# define ADCCON3_ECH_AIN7 (7 << 0)
-# define ADCCON3_ECH_AIN0_AIN1 (8 << 0)
-# define ADCCON3_ECH_AIN2_AIN3 (9 << 0)
-# define ADCCON3_ECH_AIN4_AIN5 (0xa << 0)
-# define ADCCON3_ECH_AIN6_AIN7 (0xb << 0)
-# define ADCCON3_ECH_GND (0xc << 0)
-# define ADCCON3_ECH_VREF (0xd << 0)
-# define ADCCON3_ECH_TEMP (0xe << 0)
-# define ADCCON3_ECH_VDD_3 (0xf << 0)
-
-/*
- * ADC configuration register, this selects which
- * GPIO pins are to be used as ADC inputs
- */
-__sfr at 0xF2 ADCCFG;
-
-/*
- * Watchdog timer
- */
-
-__sfr at 0xc9 WDCTL;
-
-#define WDCTL_CLEAR_FIRST (0xa << 4)
-#define WDCTL_CLEAR_SECOND (0x5 << 4)
-#define WDCTL_EN (1 << 3)
-#define WDCTL_MODE_WATCHDOG (0 << 2)
-#define WDCTL_MODE_TIMER (1 << 2)
-#define WDCTL_MODE_MASK (1 << 2)
-#define WDCTL_INT_32768 (0 << 0)
-#define WDCTL_INT_8192 (1 << 0)
-#define WDCTL_INT_512 (2 << 0)
-#define WDCTL_INT_64 (3 << 0)
-
-/*
- * Pin selectors, these set which pins are
- * using their peripheral function
- */
-__sfr at 0xF3 P0SEL;
-__sfr at 0xF4 P1SEL;
-__sfr at 0xF5 P2SEL;
-
-#define P2SEL_PRI3P1_USART0 (0 << 6)
-#define P2SEL_PRI3P1_USART1 (1 << 6)
-#define P2SEL_PRI3P1_MASK (1 << 6)
-#define P2SEL_PRI2P1_USART1 (0 << 5)
-#define P2SEL_PRI2P1_TIMER3 (1 << 5)
-#define P2SEL_PRI2P1_MASK (1 << 5)
-#define P2SEL_PRI1P1_TIMER1 (0 << 4)
-#define P2SEL_PRI1P1_TIMER4 (1 << 4)
-#define P2SEL_PRI1P1_MASK (1 << 4)
-#define P2SEL_PRI0P1_USART0 (0 << 3)
-#define P2SEL_PRI0P1_TIMER1 (1 << 3)
-#define P2SEL_PRI0P1_MASK (1 << 3)
-#define P2SEL_SELP2_4_GPIO (0 << 2)
-#define P2SEL_SELP2_4_PERIPHERAL (1 << 2)
-#define P2SEL_SELP2_4_MASK (1 << 2)
-#define P2SEL_SELP2_3_GPIO (0 << 1)
-#define P2SEL_SELP2_3_PERIPHERAL (1 << 1)
-#define P2SEL_SELP2_3_MASK (1 << 1)
-#define P2SEL_SELP2_0_GPIO (0 << 0)
-#define P2SEL_SELP2_0_PERIPHERAL (1 << 0)
-#define P2SEL_SELP2_0_MASK (1 << 0)
-
-/*
- * For pins used as GPIOs, these set which are used as outputs
- */
-__sfr at 0xFD P0DIR;
-__sfr at 0xFE P1DIR;
-__sfr at 0xFF P2DIR;
-
-#define P2DIR_PRIP0_USART0_USART1 (0 << 6)
-#define P2DIR_PRIP0_USART1_USART0 (1 << 6)
-#define P2DIR_PRIP0_TIMER1_01_USART1 (2 << 6)
-#define P2DIR_PRIP0_TIMER1_2_USART0 (3 << 6)
-#define P2DIR_PRIP0_MASK (3 << 6)
-
-__sfr at 0x8F P0INP;
-
-/* Select between tri-state and pull up/down
- * for pins P0_0 - P0_7.
- */
-#define P0INP_MDP0_7_PULL (0 << 7)
-#define P0INP_MDP0_7_TRISTATE (1 << 7)
-#define P0INP_MDP0_6_PULL (0 << 6)
-#define P0INP_MDP0_6_TRISTATE (1 << 6)
-#define P0INP_MDP0_5_PULL (0 << 5)
-#define P0INP_MDP0_5_TRISTATE (1 << 5)
-#define P0INP_MDP0_4_PULL (0 << 4)
-#define P0INP_MDP0_4_TRISTATE (1 << 4)
-#define P0INP_MDP0_3_PULL (0 << 3)
-#define P0INP_MDP0_3_TRISTATE (1 << 3)
-#define P0INP_MDP0_2_PULL (0 << 2)
-#define P0INP_MDP0_2_TRISTATE (1 << 2)
-#define P0INP_MDP0_1_PULL (0 << 1)
-#define P0INP_MDP0_1_TRISTATE (1 << 1)
-#define P0INP_MDP0_0_PULL (0 << 0)
-#define P0INP_MDP0_0_TRISTATE (1 << 0)
-
-__sfr at 0xF6 P1INP;
-
-/* Select between tri-state and pull up/down
- * for pins P1_2 - P1_7. Pins P1_0 and P1_1 are
- * always tri-stated
- */
-#define P1INP_MDP1_7_PULL (0 << 7)
-#define P1INP_MDP1_7_TRISTATE (1 << 7)
-#define P1INP_MDP1_6_PULL (0 << 6)
-#define P1INP_MDP1_6_TRISTATE (1 << 6)
-#define P1INP_MDP1_5_PULL (0 << 5)
-#define P1INP_MDP1_5_TRISTATE (1 << 5)
-#define P1INP_MDP1_4_PULL (0 << 4)
-#define P1INP_MDP1_4_TRISTATE (1 << 4)
-#define P1INP_MDP1_3_PULL (0 << 3)
-#define P1INP_MDP1_3_TRISTATE (1 << 3)
-#define P1INP_MDP1_2_PULL (0 << 2)
-#define P1INP_MDP1_2_TRISTATE (1 << 2)
-
-__sfr at 0xF7 P2INP;
-/* P2INP has three extra bits which are used to choose
- * between pull-up and pull-down when they are not tri-stated
- */
-#define P2INP_PDUP2_PULL_UP (0 << 7)
-#define P2INP_PDUP2_PULL_DOWN (1 << 7)
-#define P2INP_PDUP1_PULL_UP (0 << 6)
-#define P2INP_PDUP1_PULL_DOWN (1 << 6)
-#define P2INP_PDUP0_PULL_UP (0 << 5)
-#define P2INP_PDUP0_PULL_DOWN (1 << 5)
-
-/* For the P2 pins, choose between tri-state and pull up/down
- * mode
- */
-#define P2INP_MDP2_4_PULL (0 << 4)
-#define P2INP_MDP2_4_TRISTATE (1 << 4)
-#define P2INP_MDP2_3_PULL (0 << 3)
-#define P2INP_MDP2_3_TRISTATE (1 << 3)
-#define P2INP_MDP2_2_PULL (0 << 2)
-#define P2INP_MDP2_2_TRISTATE (1 << 2)
-#define P2INP_MDP2_1_PULL (0 << 1)
-#define P2INP_MDP2_1_TRISTATE (1 << 1)
-#define P2INP_MDP2_0_PULL (0 << 0)
-#define P2INP_MDP2_0_TRISTATE (1 << 0)
-
-/* GPIO interrupt status flags */
-__sfr at 0x89 P0IFG;
-__sfr at 0x8A P1IFG;
-__sfr at 0x8B P2IFG;
-
-#define P0IFG_USB_RESUME (1 << 7)
-
-__sfr at 0x8C PICTL;
-#define PICTL_P2IEN (1 << 5)
-#define PICTL_P0IENH (1 << 4)
-#define PICTL_P0IENL (1 << 3)
-#define PICTL_P2ICON (1 << 2)
-#define PICTL_P1ICON (1 << 1)
-#define PICTL_P0ICON (1 << 0)
-
-/* GPIO pins */
-__sfr at 0x80 P0;
-
-sbit at 0x80 P0_0;
-sbit at 0x81 P0_1;
-sbit at 0x82 P0_2;
-sbit at 0x83 P0_3;
-sbit at 0x84 P0_4;
-sbit at 0x85 P0_5;
-sbit at 0x86 P0_6;
-sbit at 0x87 P0_7;
-
-__sfr at 0x90 P1;
-
-sbit at 0x90 P1_0;
-sbit at 0x91 P1_1;
-sbit at 0x92 P1_2;
-sbit at 0x93 P1_3;
-sbit at 0x94 P1_4;
-sbit at 0x95 P1_5;
-sbit at 0x96 P1_6;
-sbit at 0x97 P1_7;
-
-__sfr at 0xa0 P2;
-
-sbit at 0xa0 P2_0;
-sbit at 0xa1 P2_1;
-sbit at 0xa2 P2_2;
-sbit at 0xa3 P2_3;
-sbit at 0xa4 P2_4;
-
-/* DMA controller */
-struct cc_dma_channel {
- uint8_t src_high;
- uint8_t src_low;
- uint8_t dst_high;
- uint8_t dst_low;
- uint8_t len_high;
- uint8_t len_low;
- uint8_t cfg0;
- uint8_t cfg1;
-};
-
-# define DMA_LEN_HIGH_VLEN_MASK (7 << 5)
-# define DMA_LEN_HIGH_VLEN_LEN (0 << 5)
-# define DMA_LEN_HIGH_VLEN_PLUS_1 (1 << 5)
-# define DMA_LEN_HIGH_VLEN (2 << 5)
-# define DMA_LEN_HIGH_VLEN_PLUS_2 (3 << 5)
-# define DMA_LEN_HIGH_VLEN_PLUS_3 (4 << 5)
-# define DMA_LEN_HIGH_MASK (0x1f)
-
-# define DMA_CFG0_WORDSIZE_8 (0 << 7)
-# define DMA_CFG0_WORDSIZE_16 (1 << 7)
-# define DMA_CFG0_TMODE_MASK (3 << 5)
-# define DMA_CFG0_TMODE_SINGLE (0 << 5)
-# define DMA_CFG0_TMODE_BLOCK (1 << 5)
-# define DMA_CFG0_TMODE_REPEATED_SINGLE (2 << 5)
-# define DMA_CFG0_TMODE_REPEATED_BLOCK (3 << 5)
-
-/*
- * DMA triggers
- */
-# define DMA_CFG0_TRIGGER_NONE 0
-# define DMA_CFG0_TRIGGER_PREV 1
-# define DMA_CFG0_TRIGGER_T1_CH0 2
-# define DMA_CFG0_TRIGGER_T1_CH1 3
-# define DMA_CFG0_TRIGGER_T1_CH2 4
-# define DMA_CFG0_TRIGGER_T2_OVFL 6
-# define DMA_CFG0_TRIGGER_T3_CH0 7
-# define DMA_CFG0_TRIGGER_T3_CH1 8
-# define DMA_CFG0_TRIGGER_T4_CH0 9
-# define DMA_CFG0_TRIGGER_T4_CH1 10
-# define DMA_CFG0_TRIGGER_IOC_0 12
-# define DMA_CFG0_TRIGGER_IOC_1 13
-# define DMA_CFG0_TRIGGER_URX0 14
-# define DMA_CFG0_TRIGGER_UTX0 15
-# define DMA_CFG0_TRIGGER_URX1 16
-# define DMA_CFG0_TRIGGER_UTX1 17
-# define DMA_CFG0_TRIGGER_FLASH 18
-# define DMA_CFG0_TRIGGER_RADIO 19
-# define DMA_CFG0_TRIGGER_ADC_CHALL 20
-# define DMA_CFG0_TRIGGER_ADC_CH0 21
-# define DMA_CFG0_TRIGGER_ADC_CH1 22
-# define DMA_CFG0_TRIGGER_ADC_CH2 23
-# define DMA_CFG0_TRIGGER_ADC_CH3 24
-# define DMA_CFG0_TRIGGER_ADC_CH4 25
-# define DMA_CFG0_TRIGGER_ADC_CH5 26
-# define DMA_CFG0_TRIGGER_ADC_CH6 27
-# define DMA_CFG0_TRIGGER_I2SRX 27
-# 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_CFG1_SRCINC_MASK (3 << 6)
-# define DMA_CFG1_SRCINC_0 (0 << 6)
-# define DMA_CFG1_SRCINC_1 (1 << 6)
-# define DMA_CFG1_SRCINC_2 (2 << 6)
-# define DMA_CFG1_SRCINC_MINUS_1 (3 << 6)
-
-# define DMA_CFG1_DESTINC_MASK (3 << 4)
-# define DMA_CFG1_DESTINC_0 (0 << 4)
-# define DMA_CFG1_DESTINC_1 (1 << 4)
-# define DMA_CFG1_DESTINC_2 (2 << 4)
-# define DMA_CFG1_DESTINC_MINUS_1 (3 << 4)
-
-# define DMA_CFG1_IRQMASK (1 << 3)
-# define DMA_CFG1_M8 (1 << 2)
-
-# define DMA_CFG1_PRIORITY_MASK (3 << 0)
-# define DMA_CFG1_PRIORITY_LOW (0 << 0)
-# define DMA_CFG1_PRIORITY_NORMAL (1 << 0)
-# define DMA_CFG1_PRIORITY_HIGH (2 << 0)
-
-/*
- * DMAARM - DMA Channel Arm
- */
-
-__sfr at 0xD6 DMAARM;
-
-# define DMAARM_ABORT (1 << 7)
-# define DMAARM_DMAARM4 (1 << 4)
-# define DMAARM_DMAARM3 (1 << 3)
-# define DMAARM_DMAARM2 (1 << 2)
-# define DMAARM_DMAARM1 (1 << 1)
-# define DMAARM_DMAARM0 (1 << 0)
-
-/*
- * DMAREQ - DMA Channel Start Request and Status
- */
-
-__sfr at 0xD7 DMAREQ;
-
-# define DMAREQ_DMAREQ4 (1 << 4)
-# define DMAREQ_DMAREQ3 (1 << 3)
-# define DMAREQ_DMAREQ2 (1 << 2)
-# define DMAREQ_DMAREQ1 (1 << 1)
-# define DMAREQ_DMAREQ0 (1 << 0)
-
-/*
- * DMA configuration 0 address
- */
-
-__sfr at 0xD5 DMA0CFGH;
-__sfr at 0xD4 DMA0CFGL;
-
-/*
- * DMA configuration 1-4 address
- */
-
-__sfr at 0xD3 DMA1CFGH;
-__sfr at 0xD2 DMA1CFGL;
-
-/*
- * DMAIRQ - DMA Interrupt Flag
- */
-
-__sfr at 0xD1 DMAIRQ;
-
-# define DMAIRQ_DMAIF4 (1 << 4)
-# define DMAIRQ_DMAIF3 (1 << 3)
-# define DMAIRQ_DMAIF2 (1 << 2)
-# define DMAIRQ_DMAIF1 (1 << 1)
-# define DMAIRQ_DMAIF0 (1 << 0)
-
-/*
- * UART registers
- */
-
-/* USART config/status registers */
-__sfr at 0x86 U0CSR;
-__sfr at 0xF8 U1CSR;
-
-# define UxCSR_MODE_UART (1 << 7)
-# define UxCSR_MODE_SPI (0 << 7)
-# define UxCSR_RE (1 << 6)
-# define UxCSR_SLAVE (1 << 5)
-# define UxCSR_MASTER (0 << 5)
-# define UxCSR_FE (1 << 4)
-# define UxCSR_ERR (1 << 3)
-# define UxCSR_RX_BYTE (1 << 2)
-# define UxCSR_TX_BYTE (1 << 1)
-# define UxCSR_ACTIVE (1 << 0)
-
-/* UART configuration registers */
-__sfr at 0xc4 U0UCR;
-__sfr at 0xfb U1UCR;
-
-# define UxUCR_FLUSH (1 << 7)
-# define UxUCR_FLOW_DISABLE (0 << 6)
-# define UxUCR_FLOW_ENABLE (1 << 6)
-# define UxUCR_D9_EVEN_PARITY (0 << 5)
-# define UxUCR_D9_ODD_PARITY (1 << 5)
-# define UxUCR_BIT9_8_BITS (0 << 4)
-# define UxUCR_BIT9_9_BITS (1 << 4)
-# define UxUCR_PARITY_DISABLE (0 << 3)
-# define UxUCR_PARITY_ENABLE (1 << 3)
-# define UxUCR_SPB_1_STOP_BIT (0 << 2)
-# define UxUCR_SPB_2_STOP_BITS (1 << 2)
-# define UxUCR_STOP_LOW (0 << 1)
-# define UxUCR_STOP_HIGH (1 << 1)
-# define UxUCR_START_LOW (0 << 0)
-# define UxUCR_START_HIGH (1 << 0)
-
-/* USART General configuration registers (mostly SPI) */
-__sfr at 0xc5 U0GCR;
-__sfr at 0xfc U1GCR;
-
-# define UxGCR_CPOL_NEGATIVE (0 << 7)
-# define UxGCR_CPOL_POSITIVE (1 << 7)
-# define UxGCR_CPHA_FIRST_EDGE (0 << 6)
-# define UxGCR_CPHA_SECOND_EDGE (1 << 6)
-# define UxGCR_ORDER_LSB (0 << 5)
-# define UxGCR_ORDER_MSB (1 << 5)
-# define UxGCR_BAUD_E_MASK (0x1f)
-# define UxGCR_BAUD_E_SHIFT 0
-
-/* USART data registers */
-__sfr at 0xc1 U0DBUF;
-__xdata __at (0xDFC1) volatile uint8_t U0DBUFXADDR;
-__sfr at 0xf9 U1DBUF;
-__xdata __at (0xDFF9) volatile uint8_t U1DBUFXADDR;
-
-/* USART baud rate registers, M value */
-__sfr at 0xc2 U0BAUD;
-__sfr at 0xfa U1BAUD;
-
-/* Flash controller */
-
-__sfr at 0xAE FCTL;
-#define FCTL_BUSY (1 << 7)
-#define FCTL_SWBSY (1 << 6)
-#define FCTL_CONTRD_ENABLE (1 << 4)
-#define FCTL_WRITE (1 << 1)
-#define FCTL_ERASE (1 << 0)
-
-/* Flash write data. Write two bytes here */
-__sfr at 0xAF FWDATA;
-__xdata __at (0xDFAF) volatile uint8_t FWDATAXADDR;
-
-/* Flash write/erase address */
-__sfr at 0xAD FADDRH;
-__sfr at 0xAC FADDRL;
-
-/* Flash timing */
-__sfr at 0xAB FWT;
-
-/* Radio */
-
-__sfr at 0xD9 RFD;
-__xdata at (0xDFD9) volatile uint8_t RFDXADDR;
-
-__sfr at 0xE9 RFIF;
-#define RFIF_IM_TXUNF (1 << 7)
-#define RFIF_IM_RXOVF (1 << 6)
-#define RFIF_IM_TIMEOUT (1 << 5)
-#define RFIF_IM_DONE (1 << 4)
-#define RFIF_IM_CS (1 << 3)
-#define RFIF_IM_PQT (1 << 2)
-#define RFIF_IM_CCA (1 << 1)
-#define RFIF_IM_SFD (1 << 0)
-
-__sfr at 0x91 RFIM;
-#define RFIM_IM_TXUNF (1 << 7)
-#define RFIM_IM_RXOVF (1 << 6)
-#define RFIM_IM_TIMEOUT (1 << 5)
-#define RFIM_IM_DONE (1 << 4)
-#define RFIM_IM_CS (1 << 3)
-#define RFIM_IM_PQT (1 << 2)
-#define RFIM_IM_CCA (1 << 1)
-#define RFIM_IM_SFD (1 << 0)
-
-__sfr at 0xE1 RFST;
-
-#define RFST_SFSTXON 0x00
-#define RFST_SCAL 0x01
-#define RFST_SRX 0x02
-#define RFST_STX 0x03
-#define RFST_SIDLE 0x04
-
-__xdata __at (0xdf00) uint8_t RF[0x3c];
-
-__xdata __at (0xdf2f) uint8_t RF_IOCFG2;
-#define RF_IOCFG2_OFF 0x2f
-
-__xdata __at (0xdf30) uint8_t RF_IOCFG1;
-#define RF_IOCFG1_OFF 0x30
-
-__xdata __at (0xdf31) uint8_t RF_IOCFG0;
-#define RF_IOCFG0_OFF 0x31
-
-__xdata __at (0xdf00) uint8_t RF_SYNC1;
-#define RF_SYNC1_OFF 0x00
-
-__xdata __at (0xdf01) uint8_t RF_SYNC0;
-#define RF_SYNC0_OFF 0x01
-
-__xdata __at (0xdf02) uint8_t RF_PKTLEN;
-#define RF_PKTLEN_OFF 0x02
-
-__xdata __at (0xdf03) uint8_t RF_PKTCTRL1;
-#define RF_PKTCTRL1_OFF 0x03
-#define PKTCTRL1_PQT_MASK (0x7 << 5)
-#define PKTCTRL1_PQT_SHIFT 5
-#define PKTCTRL1_APPEND_STATUS (1 << 2)
-#define PKTCTRL1_ADR_CHK_NONE (0 << 0)
-#define PKTCTRL1_ADR_CHK_NO_BROADCAST (1 << 0)
-#define PKTCTRL1_ADR_CHK_00_BROADCAST (2 << 0)
-#define PKTCTRL1_ADR_CHK_00_FF_BROADCAST (3 << 0)
-
-/* If APPEND_STATUS is used, two bytes will be added to the packet data */
-#define PKT_APPEND_STATUS_0_RSSI_MASK (0xff)
-#define PKT_APPEND_STATUS_0_RSSI_SHIFT 0
-#define PKT_APPEND_STATUS_1_CRC_OK (1 << 7)
-#define PKT_APPEND_STATUS_1_LQI_MASK (0x7f)
-#define PKT_APPEND_STATUS_1_LQI_SHIFT 0
-
-__xdata __at (0xdf04) uint8_t RF_PKTCTRL0;
-#define RF_PKTCTRL0_OFF 0x04
-#define RF_PKTCTRL0_WHITE_DATA (1 << 6)
-#define RF_PKTCTRL0_PKT_FORMAT_NORMAL (0 << 4)
-#define RF_PKTCTRL0_PKT_FORMAT_RANDOM (2 << 4)
-#define RF_PKTCTRL0_CRC_EN (1 << 2)
-#define RF_PKTCTRL0_LENGTH_CONFIG_FIXED (0 << 0)
-#define RF_PKTCTRL0_LENGTH_CONFIG_VARIABLE (1 << 0)
-
-__xdata __at (0xdf05) uint8_t RF_ADDR;
-#define RF_ADDR_OFF 0x05
-
-__xdata __at (0xdf06) uint8_t RF_CHANNR;
-#define RF_CHANNR_OFF 0x06
-
-__xdata __at (0xdf07) uint8_t RF_FSCTRL1;
-#define RF_FSCTRL1_OFF 0x07
-
-#define RF_FSCTRL1_FREQ_IF_SHIFT (0)
-
-__xdata __at (0xdf08) uint8_t RF_FSCTRL0;
-#define RF_FSCTRL0_OFF 0x08
-
-#define RF_FSCTRL0_FREQOFF_SHIFT (0)
-
-__xdata __at (0xdf09) uint8_t RF_FREQ2;
-#define RF_FREQ2_OFF 0x09
-
-__xdata __at (0xdf0a) uint8_t RF_FREQ1;
-#define RF_FREQ1_OFF 0x0a
-
-__xdata __at (0xdf0b) uint8_t RF_FREQ0;
-#define RF_FREQ0_OFF 0x0b
-
-__xdata __at (0xdf0c) uint8_t RF_MDMCFG4;
-#define RF_MDMCFG4_OFF 0x0c
-
-#define RF_MDMCFG4_CHANBW_E_SHIFT 6
-#define RF_MDMCFG4_CHANBW_M_SHIFT 4
-#define RF_MDMCFG4_DRATE_E_SHIFT 0
-
-__xdata __at (0xdf0d) uint8_t RF_MDMCFG3;
-#define RF_MDMCFG3_OFF 0x0d
-
-#define RF_MDMCFG3_DRATE_M_SHIFT 0
-
-__xdata __at (0xdf0e) uint8_t RF_MDMCFG2;
-#define RF_MDMCFG2_OFF 0x0e
-
-#define RF_MDMCFG2_DEM_DCFILT_OFF (1 << 7)
-#define RF_MDMCFG2_DEM_DCFILT_ON (0 << 7)
-
-#define RF_MDMCFG2_MOD_FORMAT_MASK (7 << 4)
-#define RF_MDMCFG2_MOD_FORMAT_2_FSK (0 << 4)
-#define RF_MDMCFG2_MOD_FORMAT_GFSK (1 << 4)
-#define RF_MDMCFG2_MOD_FORMAT_ASK_OOK (3 << 4)
-#define RF_MDMCFG2_MOD_FORMAT_MSK (7 << 4)
-
-#define RF_MDMCFG2_MANCHESTER_EN (1 << 3)
-
-#define RF_MDMCFG2_SYNC_MODE_MASK (0x7 << 0)
-#define RF_MDMCFG2_SYNC_MODE_NONE (0x0 << 0)
-#define RF_MDMCFG2_SYNC_MODE_15_16 (0x1 << 0)
-#define RF_MDMCFG2_SYNC_MODE_16_16 (0x2 << 0)
-#define RF_MDMCFG2_SYNC_MODE_30_32 (0x3 << 0)
-#define RF_MDMCFG2_SYNC_MODE_NONE_THRES (0x4 << 0)
-#define RF_MDMCFG2_SYNC_MODE_15_16_THRES (0x5 << 0)
-#define RF_MDMCFG2_SYNC_MODE_16_16_THRES (0x6 << 0)
-#define RF_MDMCFG2_SYNC_MODE_30_32_THRES (0x7 << 0)
-
-__xdata __at (0xdf0f) uint8_t RF_MDMCFG1;
-#define RF_MDMCFG1_OFF 0x0f
-
-#define RF_MDMCFG1_FEC_EN (1 << 7)
-#define RF_MDMCFG1_FEC_DIS (0 << 7)
-
-#define RF_MDMCFG1_NUM_PREAMBLE_MASK (7 << 4)
-#define RF_MDMCFG1_NUM_PREAMBLE_2 (0 << 4)
-#define RF_MDMCFG1_NUM_PREAMBLE_3 (1 << 4)
-#define RF_MDMCFG1_NUM_PREAMBLE_4 (2 << 4)
-#define RF_MDMCFG1_NUM_PREAMBLE_6 (3 << 4)
-#define RF_MDMCFG1_NUM_PREAMBLE_8 (4 << 4)
-#define RF_MDMCFG1_NUM_PREAMBLE_12 (5 << 4)
-#define RF_MDMCFG1_NUM_PREAMBLE_16 (6 << 4)
-#define RF_MDMCFG1_NUM_PREAMBLE_24 (7 << 4)
-
-#define RF_MDMCFG1_CHANSPC_E_MASK (3 << 0)
-#define RF_MDMCFG1_CHANSPC_E_SHIFT (0)
-
-__xdata __at (0xdf10) uint8_t RF_MDMCFG0;
-#define RF_MDMCFG0_OFF 0x10
-
-#define RF_MDMCFG0_CHANSPC_M_SHIFT (0)
-
-__xdata __at (0xdf11) uint8_t RF_DEVIATN;
-#define RF_DEVIATN_OFF 0x11
-
-#define RF_DEVIATN_DEVIATION_E_SHIFT 4
-#define RF_DEVIATN_DEVIATION_M_SHIFT 0
-
-__xdata __at (0xdf12) uint8_t RF_MCSM2;
-#define RF_MCSM2_OFF 0x12
-#define RF_MCSM2_RX_TIME_RSSI (1 << 4)
-#define RF_MCSM2_RX_TIME_QUAL (1 << 3)
-#define RF_MCSM2_RX_TIME_MASK (0x7)
-#define RF_MCSM2_RX_TIME_SHIFT 0
-#define RF_MCSM2_RX_TIME_END_OF_PACKET (7)
-
-__xdata __at (0xdf13) uint8_t RF_MCSM1;
-#define RF_MCSM1_OFF 0x13
-#define RF_MCSM1_CCA_MODE_ALWAYS (0 << 4)
-#define RF_MCSM1_CCA_MODE_RSSI_BELOW (1 << 4)
-#define RF_MCSM1_CCA_MODE_UNLESS_RECEIVING (2 << 4)
-#define RF_MCSM1_CCA_MODE_RSSI_BELOW_UNLESS_RECEIVING (3 << 4)
-#define RF_MCSM1_RXOFF_MODE_IDLE (0 << 2)
-#define RF_MCSM1_RXOFF_MODE_FSTXON (1 << 2)
-#define RF_MCSM1_RXOFF_MODE_TX (2 << 2)
-#define RF_MCSM1_RXOFF_MODE_RX (3 << 2)
-#define RF_MCSM1_TXOFF_MODE_IDLE (0 << 0)
-#define RF_MCSM1_TXOFF_MODE_FSTXON (1 << 0)
-#define RF_MCSM1_TXOFF_MODE_TX (2 << 0)
-#define RF_MCSM1_TXOFF_MODE_RX (3 << 0)
-
-__xdata __at (0xdf14) uint8_t RF_MCSM0;
-#define RF_MCSM0_OFF 0x14
-#define RF_MCSM0_FS_AUTOCAL_NEVER (0 << 4)
-#define RF_MCSM0_FS_AUTOCAL_FROM_IDLE (1 << 4)
-#define RF_MCSM0_FS_AUTOCAL_TO_IDLE (2 << 4)
-#define RF_MCSM0_FS_AUTOCAL_TO_IDLE_EVERY_4 (3 << 4)
-#define RF_MCSM0_MAGIC_3 (1 << 3)
-#define RF_MCSM0_MAGIC_2 (1 << 2)
-#define RF_MCSM0_CLOSE_IN_RX_0DB (0 << 0)
-#define RF_MCSM0_CLOSE_IN_RX_6DB (1 << 0)
-#define RF_MCSM0_CLOSE_IN_RX_12DB (2 << 0)
-#define RF_MCSM0_CLOSE_IN_RX_18DB (3 << 0)
-
-__xdata __at (0xdf15) uint8_t RF_FOCCFG;
-#define RF_FOCCFG_OFF 0x15
-#define RF_FOCCFG_FOC_BS_CS_GATE (1 << 5)
-#define RF_FOCCFG_FOC_PRE_K_1K (0 << 3)
-#define RF_FOCCFG_FOC_PRE_K_2K (1 << 3)
-#define RF_FOCCFG_FOC_PRE_K_3K (2 << 3)
-#define RF_FOCCFG_FOC_PRE_K_4K (3 << 3)
-#define RF_FOCCFG_FOC_POST_K_PRE_K (0 << 2)
-#define RF_FOCCFG_FOC_POST_K_PRE_K_OVER_2 (1 << 2)
-#define RF_FOCCFG_FOC_LIMIT_0 (0 << 0)
-#define RF_FOCCFG_FOC_LIMIT_BW_OVER_8 (1 << 0)
-#define RF_FOCCFG_FOC_LIMIT_BW_OVER_4 (2 << 0)
-#define RF_FOCCFG_FOC_LIMIT_BW_OVER_2 (3 << 0)
-
-__xdata __at (0xdf16) uint8_t RF_BSCFG;
-#define RF_BSCFG_OFF 0x16
-#define RF_BSCFG_BS_PRE_K_1K (0 << 6)
-#define RF_BSCFG_BS_PRE_K_2K (1 << 6)
-#define RF_BSCFG_BS_PRE_K_3K (2 << 6)
-#define RF_BSCFG_BS_PRE_K_4K (3 << 6)
-#define RF_BSCFG_BS_PRE_KP_1KP (0 << 4)
-#define RF_BSCFG_BS_PRE_KP_2KP (1 << 4)
-#define RF_BSCFG_BS_PRE_KP_3KP (2 << 4)
-#define RF_BSCFG_BS_PRE_KP_4KP (3 << 4)
-#define RF_BSCFG_BS_POST_KI_PRE_KI (0 << 3)
-#define RF_BSCFG_BS_POST_KI_PRE_KI_OVER_2 (1 << 3)
-#define RF_BSCFG_BS_POST_KP_PRE_KP (0 << 2)
-#define RF_BSCFG_BS_POST_KP_PRE_KP_OVER_2 (1 << 2)
-#define RF_BSCFG_BS_LIMIT_0 (0 << 0)
-#define RF_BSCFG_BS_LIMIT_3_125 (1 << 0)
-#define RF_BSCFG_BS_LIMIT_6_25 (2 << 0)
-#define RF_BSCFG_BS_LIMIT_12_5 (3 << 0)
-
-__xdata __at (0xdf17) uint8_t RF_AGCCTRL2;
-#define RF_AGCCTRL2_OFF 0x17
-
-__xdata __at (0xdf18) uint8_t RF_AGCCTRL1;
-#define RF_AGCCTRL1_OFF 0x18
-
-__xdata __at (0xdf19) uint8_t RF_AGCCTRL0;
-#define RF_AGCCTRL0_OFF 0x19
-
-__xdata __at (0xdf1a) uint8_t RF_FREND1;
-#define RF_FREND1_OFF 0x1a
-
-#define RF_FREND1_LNA_CURRENT_SHIFT 6
-#define RF_FREND1_LNA2MIX_CURRENT_SHIFT 4
-#define RF_FREND1_LODIV_BUF_CURRENT_RX_SHIFT 2
-#define RF_FREND1_MIX_CURRENT_SHIFT 0
-
-__xdata __at (0xdf1b) uint8_t RF_FREND0;
-#define RF_FREND0_OFF 0x1b
-
-#define RF_FREND0_LODIV_BUF_CURRENT_TX_MASK (0x3 << 4)
-#define RF_FREND0_LODIV_BUF_CURRENT_TX_SHIFT 4
-#define RF_FREND0_PA_POWER_MASK (0x7)
-#define RF_FREND0_PA_POWER_SHIFT 0
-
-__xdata __at (0xdf1c) uint8_t RF_FSCAL3;
-#define RF_FSCAL3_OFF 0x1c
-
-__xdata __at (0xdf1d) uint8_t RF_FSCAL2;
-#define RF_FSCAL2_OFF 0x1d
-
-__xdata __at (0xdf1e) uint8_t RF_FSCAL1;
-#define RF_FSCAL1_OFF 0x1e
-
-__xdata __at (0xdf1f) uint8_t RF_FSCAL0;
-#define RF_FSCAL0_OFF 0x1f
-
-__xdata __at (0xdf23) uint8_t RF_TEST2;
-#define RF_TEST2_OFF 0x23
-
-#define RF_TEST2_NORMAL_MAGIC 0x88
-#define RF_TEST2_RX_LOW_DATA_RATE_MAGIC 0x81
-
-__xdata __at (0xdf24) uint8_t RF_TEST1;
-#define RF_TEST1_OFF 0x24
-
-#define RF_TEST1_TX_MAGIC 0x31
-#define RF_TEST1_RX_LOW_DATA_RATE_MAGIC 0x35
-
-__xdata __at (0xdf25) uint8_t RF_TEST0;
-#define RF_TEST0_OFF 0x25
-
-#define RF_TEST0_7_2_MASK (0xfc)
-#define RF_TEST0_VCO_SEL_CAL_EN (1 << 1)
-#define RF_TEST0_0_MASK (1)
-
-/* These are undocumented, and must be computed
- * using the provided tool.
- */
-__xdata __at (0xdf27) uint8_t RF_PA_TABLE7;
-#define RF_PA_TABLE7_OFF 0x27
-
-__xdata __at (0xdf28) uint8_t RF_PA_TABLE6;
-#define RF_PA_TABLE6_OFF 0x28
-
-__xdata __at (0xdf29) uint8_t RF_PA_TABLE5;
-#define RF_PA_TABLE5_OFF 0x29
-
-__xdata __at (0xdf2a) uint8_t RF_PA_TABLE4;
-#define RF_PA_TABLE4_OFF 0x2a
-
-__xdata __at (0xdf2b) uint8_t RF_PA_TABLE3;
-#define RF_PA_TABLE3_OFF 0x2b
-
-__xdata __at (0xdf2c) uint8_t RF_PA_TABLE2;
-#define RF_PA_TABLE2_OFF 0x2c
-
-__xdata __at (0xdf2d) uint8_t RF_PA_TABLE1;
-#define RF_PA_TABLE1_OFF 0x2d
-
-__xdata __at (0xdf2e) uint8_t RF_PA_TABLE0;
-#define RF_PA_TABLE0_OFF 0x2e
-
-__xdata __at (0xdf36) uint8_t RF_PARTNUM;
-#define RF_PARTNUM_OFF 0x36
-
-__xdata __at (0xdf37) uint8_t RF_VERSION;
-#define RF_VERSION_OFF 0x37
-
-__xdata __at (0xdf38) uint8_t RF_FREQEST;
-#define RF_FREQEST_OFF 0x38
-
-__xdata __at (0xdf39) uint8_t RF_LQI;
-#define RF_LQI_OFF 0x39
-
-#define RF_LQI_CRC_OK (1 << 7)
-#define RF_LQI_LQI_EST_MASK (0x7f)
-
-__xdata __at (0xdf3a) uint8_t RF_RSSI;
-#define RF_RSSI_OFF 0x3a
-
-__xdata __at (0xdf3b) uint8_t RF_MARCSTATE;
-#define RF_MARCSTATE_OFF 0x3b
-
-#define RF_MARCSTATE_MASK 0x1f
-#define RF_MARCSTATE_SLEEP 0x00
-#define RF_MARCSTATE_IDLE 0x01
-#define RF_MARCSTATE_VCOON_MC 0x03
-#define RF_MARCSTATE_REGON_MC 0x04
-#define RF_MARCSTATE_MANCAL 0x05
-#define RF_MARCSTATE_VCOON 0x06
-#define RF_MARCSTATE_REGON 0x07
-#define RF_MARCSTATE_STARTCAL 0x08
-#define RF_MARCSTATE_BWBOOST 0x09
-#define RF_MARCSTATE_FS_LOCK 0x0a
-#define RF_MARCSTATE_IFADCON 0x0b
-#define RF_MARCSTATE_ENDCAL 0x0c
-#define RF_MARCSTATE_RX 0x0d
-#define RF_MARCSTATE_RX_END 0x0e
-#define RF_MARCSTATE_RX_RST 0x0f
-#define RF_MARCSTATE_TXRX_SWITCH 0x10
-#define RF_MARCSTATE_RX_OVERFLOW 0x11
-#define RF_MARCSTATE_FSTXON 0x12
-#define RF_MARCSTATE_TX 0x13
-#define RF_MARCSTATE_TX_END 0x14
-#define RF_MARCSTATE_RXTX_SWITCH 0x15
-#define RF_MARCSTATE_TX_UNDERFLOW 0x16
-
-
-__xdata __at (0xdf3c) uint8_t RF_PKTSTATUS;
-#define RF_PKTSTATUS_OFF 0x3c
-
-#define RF_PKTSTATUS_CRC_OK (1 << 7)
-#define RF_PKTSTATUS_CS (1 << 6)
-#define RF_PKTSTATUS_PQT_REACHED (1 << 5)
-#define RF_PKTSTATUS_CCA (1 << 4)
-#define RF_PKTSTATUS_SFD (1 << 3)
-
-__xdata __at (0xdf3d) uint8_t RF_VCO_VC_DAC;
-#define RF_VCO_VC_DAC_OFF 0x3d
-
-#endif
--- /dev/null
+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$@ $<
--- /dev/null
+/*-------------------------------------------------------------------------
+
+ _bp.c :- just declares bp as a variable
+
+ Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999)
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This library 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 Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+
+__data unsigned char bp ;
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_pins.h"
+
+volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING];
+#if HAS_ACCEL_REF
+volatile __xdata uint16_t ao_accel_ref[AO_ADC_RING];
+#endif
+volatile __data uint8_t ao_adc_head;
+
+void
+ao_adc_poll(void)
+{
+#if HAS_ACCEL_REF
+ ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 2;
+#else
+# ifdef TELENANO_V_0_1
+ ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 1;
+# else
+ ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 0;
+# endif
+#endif
+}
+
+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));
+}
+
+void
+ao_adc_isr(void) __interrupt 1
+{
+ uint8_t sequence;
+ uint8_t __xdata *a;
+
+ sequence = (ADCCON2 & ADCCON2_SCH_MASK) >> ADCCON2_SCH_SHIFT;
+#if IGNITE_ON_P2
+ /* TeleMetrum readings */
+#if HAS_ACCEL_REF
+ if (sequence == 2) {
+ a = (uint8_t __xdata *) (&ao_accel_ref[ao_adc_head]);
+ sequence = 0;
+ } else
+#endif
+ {
+ if (sequence == ADCCON3_ECH_TEMP)
+ sequence = 2;
+ a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].accel + sequence);
+ sequence++;
+ }
+#define GOT_ADC
+ a[0] = ADCL;
+ a[1] = ADCH;
+ if (sequence < 6) {
+#if HAS_EXTERNAL_TEMP == 0
+ /* start next channel conversion */
+ /* v0.2 replaces external temp sensor with internal one */
+ if (sequence == 2)
+ ADCCON3 = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP;
+ else
+#endif
+ ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | sequence;
+ }
+#endif
+
+#if IGNITE_ON_P0
+ /* TeleMini readings */
+ a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].pres);
+#ifdef TELEMINI_V_1_0
+ switch (sequence) {
+ case 0:
+ /* pressure */
+ a += 0;
+ sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 1;
+ break;
+ case 1:
+ /* drogue sense */
+ a += 6;
+ sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 2;
+ break;
+ case 2:
+ /* main sense */
+ a += 8;
+ sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 3;
+ break;
+ case 3:
+ /* battery */
+ a += 4;
+ sequence = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP;
+ break;
+ case ADCCON3_ECH_TEMP:
+ a += 2;
+ sequence = 0;
+ break;
+ }
+#define GOT_ADC
+#endif
+#ifdef TELENANO_V_0_1
+ switch (sequence) {
+ case 1:
+ /* pressure */
+ a += 0;
+ sequence = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 3;
+ break;
+ case 3:
+ /* battery */
+ a += 4;
+ sequence = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP;
+ break;
+ case ADCCON3_ECH_TEMP:
+ a += 2;
+ sequence = 0;
+ break;
+ }
+#define GOT_ADC
+#endif
+ a[0] = ADCL;
+ a[1] = ADCH;
+ if (sequence) {
+ /* Start next conversion */
+ ADCCON3 = sequence;
+ }
+#endif
+#ifndef GOT_ADC
+#error No known ADC configuration set
+#endif
+
+ else {
+ /* record this conversion series */
+ ao_adc_ring[ao_adc_head].tick = ao_time();
+ ao_adc_head = ao_adc_ring_next(ao_adc_head);
+ ao_wakeup(DATA_TO_XDATA(&ao_adc_head));
+ }
+}
+
+static void
+ao_adc_dump(void) __reentrant
+{
+ static __xdata struct ao_adc packet;
+ ao_adc_get(&packet);
+ printf("tick: %5u accel: %5d pres: %5d temp: %5d batt: %5d drogue: %5d main: %5d\n",
+ packet.tick, packet.accel, packet.pres, packet.temp,
+ packet.v_batt, packet.sense_d, packet.sense_m);
+}
+
+__code struct ao_cmds ao_adc_cmds[] = {
+ { ao_adc_dump, "a\0Current ADC" },
+ { 0, NULL },
+};
+
+void
+ao_adc_init(void)
+{
+#if IGNITE_ON_P2
+ /* TeleMetrum configuration */
+ ADCCFG = ((1 << 0) | /* acceleration */
+ (1 << 1) | /* pressure */
+#if HAS_EXTERNAL_TEMP
+ (1 << 2) | /* v0.1 temperature */
+#endif
+ (1 << 3) | /* battery voltage */
+ (1 << 4) | /* drogue sense */
+ (1 << 5)); /* main sense */
+#endif
+
+#if IGNITE_ON_P0
+ /* TeleMini configuration */
+ ADCCFG = ((1 << 0) | /* pressure */
+ (1 << 1) | /* drogue sense */
+ (1 << 2) | /* main sense */
+ (1 << 3)); /* battery voltage */
+#endif
+
+ /* enable interrupts */
+ ADCIF = 0;
+ IEN0 |= IEN0_ADCIE;
+ ao_cmd_register(&ao_adc_cmds[0]);
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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
+ao_beep(uint8_t beep)
+{
+ if (beep == 0) {
+ P2_0 = 0;
+ P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_GPIO;
+ T4CTL = 0;
+ } else {
+ P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_PERIPHERAL;
+ T4CC0 = beep;
+ T4CTL = TxCTL_DIV_32 | TxCTL_MODE_MODULO | TxCTL_START;
+ }
+}
+
+void
+ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant
+{
+ ao_beep(beep);
+ ao_delay(ticks);
+ ao_beep(0);
+}
+
+void
+ao_beep_init(void)
+{
+ /* Our beeper is on P2_0, which is hooked to timer 4 using
+ * configuration alternative 2
+ */
+ P2_0 = 0;
+ P2SEL = (P2SEL & ~P2SEL_SELP2_0_MASK) | P2SEL_SELP2_0_GPIO;
+ PERCFG = (PERCFG & ~PERCFG_T4CFG_ALT_MASK) | PERCFG_T4CFG_ALT_2;
+ T4CCTL0 = TxCCTLy_CMP_TOGGLE|TxCCTLy_CMP_MODE_ENABLE;
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_pins.h"
+
+static void
+ao_dbg_send_bits(uint8_t msk, uint8_t val) __reentrant
+{
+ DBG_PORT = (DBG_PORT & ~msk) | (val & msk);
+ _asm
+ nop
+ nop
+ _endasm;
+}
+
+void
+ao_dbg_send_byte(uint8_t byte)
+{
+ __pdata uint8_t b, d;
+
+ DBG_PORT |= DBG_DATA;
+ DBG_PORT_DIR |= DBG_DATA;
+ for (b = 0; b < 8; b++) {
+ d = 0;
+ if (byte & 0x80)
+ d = DBG_DATA;
+ byte <<= 1;
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, DBG_CLOCK|d);
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, 0 |d);
+ }
+ DBG_PORT_DIR &= ~DBG_DATA;
+}
+
+uint8_t
+ao_dbg_recv_byte(void)
+{
+ __pdata uint8_t byte, b;
+
+ byte = 0;
+ for (b = 0; b < 8; b++) {
+ byte = byte << 1;
+ ao_dbg_send_bits(DBG_CLOCK, DBG_CLOCK);
+ if (DBG_DATA_PIN)
+ byte |= 1;
+ ao_dbg_send_bits(DBG_CLOCK, 0);
+ }
+ return byte;
+}
+
+/* 8051 instructions
+ */
+#define NOP 0x00
+#define MOV_direct_data 0x75
+#define LJMP 0x02
+#define MOV_Rn_data(n) (0x78 | (n))
+#define DJNZ_Rn_rel(n) (0xd8 | (n))
+#define MOV_A_direct 0xe5
+#define MOV_direct1_direct2 0x85
+#define MOV_direct_A 0xf5
+#define MOV_DPTR_data16 0x90
+#define MOV_A_data 0x74
+#define MOVX_atDPTR_A 0xf0
+#define MOVX_A_atDPTR 0xe0
+#define INC_DPTR 0xa3
+#define TRAP 0xa5
+#define SJMP 0x80
+#define JB 0x20
+
+#define DEBUG_INSTR(l) (0x54 | (l))
+
+#define SFR_PSW 0xD0
+#define SFR_DPL0 0x82
+#define SFR_DPH0 0x83
+#define SFR_DPL1 0x84
+#define SFR_DPH1 0x85
+
+__pdata uint8_t save_acc;
+__pdata uint8_t save_psw;
+__pdata uint8_t save_dpl0;
+__pdata uint8_t save_dph0;
+__pdata uint8_t save_dpl1;
+__pdata uint8_t save_dph1;
+
+static uint8_t
+ao_dbg_inst1(uint8_t a) __reentrant
+{
+ ao_dbg_send_byte(DEBUG_INSTR(1));
+ ao_dbg_send_byte(a);
+ return ao_dbg_recv_byte();
+}
+
+static uint8_t
+ao_dbg_inst2(uint8_t a, uint8_t b) __reentrant
+{
+ ao_dbg_send_byte(DEBUG_INSTR(2));
+ ao_dbg_send_byte(a);
+ ao_dbg_send_byte(b);
+ return ao_dbg_recv_byte();
+}
+
+static uint8_t
+ao_dbg_inst3(uint8_t a, uint8_t b, uint8_t c) __reentrant
+{
+ ao_dbg_send_byte(DEBUG_INSTR(3));
+ ao_dbg_send_byte(a);
+ ao_dbg_send_byte(b);
+ ao_dbg_send_byte(c);
+ return ao_dbg_recv_byte();
+}
+
+void
+ao_dbg_start_transfer(uint16_t addr)
+{
+ save_acc = ao_dbg_inst1(NOP);
+ save_psw = ao_dbg_inst2(MOV_A_direct, SFR_PSW);
+ save_dpl0 = ao_dbg_inst2(MOV_A_direct, SFR_DPL0);
+ save_dph0 = ao_dbg_inst2(MOV_A_direct, SFR_DPH0);
+ save_dpl1 = ao_dbg_inst2(MOV_A_direct, SFR_DPL1);
+ save_dph1 = ao_dbg_inst2(MOV_A_direct, SFR_DPH1);
+ ao_dbg_inst3(MOV_DPTR_data16, addr >> 8, addr);
+}
+
+void
+ao_dbg_end_transfer(void)
+{
+ ao_dbg_inst3(MOV_direct_data, SFR_DPL0, save_dpl0);
+ ao_dbg_inst3(MOV_direct_data, SFR_DPH0, save_dph0);
+ ao_dbg_inst3(MOV_direct_data, SFR_DPL1, save_dpl1);
+ ao_dbg_inst3(MOV_direct_data, SFR_DPH1, save_dph1);
+ ao_dbg_inst3(MOV_direct_data, SFR_PSW, save_psw);
+ ao_dbg_inst2(MOV_A_data, save_acc);
+}
+
+void
+ao_dbg_write_byte(uint8_t byte)
+{
+ ao_dbg_inst2(MOV_A_data, byte);
+ ao_dbg_inst1(MOVX_atDPTR_A);
+ ao_dbg_inst1(INC_DPTR);
+}
+
+uint8_t
+ao_dbg_read_byte(void)
+{
+ ao_dbg_inst1(MOVX_A_atDPTR);
+ return ao_dbg_inst1(INC_DPTR);
+}
+
+static void
+ao_dbg_set_pins(void)
+{
+ /* Make the DBG pins GPIOs. On TeleMetrum, this will
+ * disable the SPI link, so don't expect SPI to work after
+ * using the debugger.
+ */
+ DBG_PORT_SEL &= ~(DBG_CLOCK|DBG_DATA|DBG_RESET_N);
+
+ /* make DBG_DATA tri-state */
+ DBG_PORT_INP |= DBG_DATA;
+
+ /* Raise RESET_N and CLOCK */
+ DBG_PORT |= DBG_RESET_N | DBG_CLOCK;
+
+ /* RESET_N and CLOCK are outputs now */
+ DBG_PORT_DIR |= DBG_RESET_N | DBG_CLOCK;
+ DBG_PORT_DIR &= ~DBG_DATA;
+}
+
+static void
+ao_dbg_long_delay(void)
+{
+ uint8_t n;
+
+ for (n = 0; n < 20; n++)
+ _asm nop _endasm;
+}
+
+#define AO_RESET_LOW_DELAY AO_MS_TO_TICKS(100)
+#define AO_RESET_HIGH_DELAY AO_MS_TO_TICKS(100)
+
+void
+ao_dbg_debug_mode(void)
+{
+ ao_dbg_set_pins();
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA| 0 );
+ ao_delay(AO_RESET_LOW_DELAY);
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA| 0 );
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, 0 |DBG_DATA|DBG_RESET_N);
+ ao_delay(AO_RESET_HIGH_DELAY);
+}
+
+void
+ao_dbg_reset(void)
+{
+ ao_dbg_set_pins();
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
+ ao_delay(AO_RESET_LOW_DELAY);
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA| 0 );
+ ao_dbg_long_delay();
+ ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
+ ao_delay(AO_RESET_HIGH_DELAY);
+}
+
+static void
+debug_enable(void)
+{
+ ao_dbg_debug_mode();
+}
+
+static void
+debug_reset(void)
+{
+ ao_dbg_reset();
+}
+
+static void
+debug_put(void)
+{
+ for (;;) {
+ ao_cmd_white ();
+ if (ao_cmd_lex_c == '\n')
+ break;
+ ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ break;
+ ao_dbg_send_byte(ao_cmd_lex_i);
+ }
+}
+
+static void
+debug_get(void)
+{
+ __pdata uint16_t count;
+ __pdata uint16_t i;
+ __pdata uint8_t byte;
+ ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ count = ao_cmd_lex_i;
+ if (count > 256) {
+ ao_cmd_status = ao_cmd_syntax_error;
+ return;
+ }
+ for (i = 0; i < count; i++) {
+ if (i && (i & 7) == 0)
+ putchar('\n');
+ byte = ao_dbg_recv_byte();
+ ao_cmd_put8(byte);
+ putchar(' ');
+ }
+ putchar('\n');
+}
+
+static uint8_t
+getnibble(void)
+{
+ __pdata char c;
+
+ c = getchar();
+ if ('0' <= c && c <= '9')
+ return c - '0';
+ if ('a' <= c && c <= 'f')
+ return c - ('a' - 10);
+ if ('A' <= c && c <= 'F')
+ return c - ('A' - 10);
+ ao_cmd_status = ao_cmd_lex_error;
+ return 0;
+}
+
+static void
+debug_input(void)
+{
+ __pdata uint16_t count;
+ __pdata uint16_t addr;
+ __pdata uint8_t b;
+ __pdata uint8_t i;
+
+ ao_cmd_hex();
+ count = ao_cmd_lex_i;
+ ao_cmd_hex();
+ addr = ao_cmd_lex_i;
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ ao_dbg_start_transfer(addr);
+ i = 0;
+ while (count--) {
+ if (!(i++ & 7))
+ putchar('\n');
+ b = ao_dbg_read_byte();
+ ao_cmd_put8(b);
+ }
+ ao_dbg_end_transfer();
+ putchar('\n');
+}
+
+static void
+debug_output(void)
+{
+ __pdata uint16_t count;
+ __pdata uint16_t addr;
+ __pdata uint8_t b;
+
+ ao_cmd_hex();
+ count = ao_cmd_lex_i;
+ ao_cmd_hex();
+ addr = ao_cmd_lex_i;
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ ao_dbg_start_transfer(addr);
+ while (count--) {
+ b = getnibble() << 4;
+ b |= getnibble();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ ao_dbg_write_byte(b);
+ }
+ ao_dbg_end_transfer();
+}
+
+__code struct ao_cmds ao_dbg_cmds[7] = {
+ { debug_enable, "D\0Enable debug" },
+ { debug_get, "G <count>\0Get data" },
+ { debug_input, "I <count> <addr>\0Input <count> at <addr>" },
+ { debug_output, "O <count> <addr>\0Output <count> at <addr>" },
+ { debug_put, "P <byte> ...\0Put data" },
+ { debug_reset, "R\0Reset" },
+ { 0, NULL },
+};
+
+void
+ao_dbg_init(void)
+{
+ ao_cmd_register(&ao_dbg_cmds[0]);
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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 NUM_DMA 5
+
+/*
+ * The config address for DMA0 is programmed
+ * separately from that of DMA1-4, but for simplicity,
+ * we make them all contiguous.
+ */
+
+static __xdata struct cc_dma_channel ao_dma_config[NUM_DMA];
+static __xdata uint8_t * __xdata ao_dma_done[NUM_DMA];
+static __data uint8_t ao_next_dma;
+
+uint8_t
+ao_dma_alloc(__xdata uint8_t *done)
+{
+ uint8_t id;
+
+ if (ao_next_dma == NUM_DMA)
+ ao_panic(AO_PANIC_DMA);
+ id = ao_next_dma++;
+ ao_dma_done[id] = done;
+
+ /* When the first dma object is allocated, set up the DMA
+ * controller
+ */
+ if (id == 0) {
+ DMAIRQ = 0;
+ DMAIF = 0;
+ IEN1 |= IEN1_DMAIE;
+ }
+
+ return id;
+}
+
+void
+ao_dma_set_transfer(uint8_t id,
+ void __xdata *srcaddr,
+ void __xdata *dstaddr,
+ uint16_t count,
+ uint8_t cfg0,
+ uint8_t cfg1)
+{
+ if (DMAARM & (1 << id))
+ ao_panic(AO_PANIC_DMA);
+ ao_dma_config[id].src_high = ((uint16_t) srcaddr) >> 8;
+ ao_dma_config[id].src_low = ((uint16_t) srcaddr);
+ ao_dma_config[id].dst_high = ((uint16_t) dstaddr) >> 8;
+ ao_dma_config[id].dst_low = ((uint16_t) dstaddr);
+ ao_dma_config[id].len_high = count >> 8;
+ ao_dma_config[id].len_low = count;
+ ao_dma_config[id].cfg0 = cfg0;
+ ao_dma_config[id].cfg1 = cfg1 | DMA_CFG1_IRQMASK;
+ if (id == 0) {
+ DMA0CFGH = ((uint16_t) (&ao_dma_config[0])) >> 8;
+ DMA0CFGL = ((uint16_t) (&ao_dma_config[0]));
+ } else {
+ DMA1CFGH = ((uint16_t) (&ao_dma_config[1])) >> 8;
+ DMA1CFGL = ((uint16_t) (&ao_dma_config[1]));
+ }
+}
+
+#define nop() _asm nop _endasm;
+
+void
+ao_dma_start(uint8_t id)
+{
+ uint8_t mask = (1 << id);
+ DMAIRQ &= ~mask;
+ DMAARM = 0x80 | mask;
+ nop(); nop(); nop(); nop();
+ nop(); nop(); nop(); nop();
+ *(ao_dma_done[id]) = 0;
+ DMAARM = mask;
+ nop(); nop(); nop(); nop();
+ nop(); nop(); nop(); nop();
+ nop();
+}
+
+void
+ao_dma_trigger(uint8_t id)
+{
+ DMAREQ |= (1 << id);
+}
+
+void
+ao_dma_abort(uint8_t id)
+{
+ uint8_t mask = (1 << id);
+ DMAARM = 0x80 | mask;
+ DMAIRQ &= ~mask;
+}
+
+void
+ao_dma_isr(void) __interrupt 8
+{
+ uint8_t id, mask;
+
+ /* Find the first DMA channel which is done */
+ mask = 1;
+ for (id = 0; id < ao_next_dma; id++) {
+ if (DMAIRQ & mask) {
+ /* Clear CPU interrupt flag */
+ DMAIF = 0;
+ /* Clear the completed ID */
+ DMAIRQ = ~mask;
+ *(ao_dma_done[id]) = 1;
+ ao_wakeup(ao_dma_done[id]);
+ break;
+ }
+ mask <<= 1;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_ignition ao_ignition[2];
+
+void
+ao_ignite(enum ao_igniter igniter) __critical
+{
+ ao_ignition[igniter].request = 1;
+ ao_wakeup(&ao_ignition);
+}
+
+enum ao_igniter_status
+ao_igniter_status(enum ao_igniter igniter)
+{
+ __xdata struct ao_adc adc;
+ __pdata int16_t value;
+ __pdata uint8_t request, firing, fired;
+
+ __critical {
+ ao_adc_get(&adc);
+ request = ao_ignition[igniter].request;
+ fired = ao_ignition[igniter].fired;
+ firing = ao_ignition[igniter].firing;
+ }
+ if (firing || (request && !fired))
+ return ao_igniter_active;
+
+ value = (AO_IGNITER_CLOSED>>1);
+ switch (igniter) {
+ case ao_igniter_drogue:
+ value = adc.sense_d;
+ break;
+ case ao_igniter_main:
+ value = adc.sense_m;
+ 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_igniter_fire(enum ao_igniter igniter) __critical
+{
+ ao_ignition[igniter].firing = 1;
+ switch(ao_config.ignite_mode) {
+ case AO_IGNITE_MODE_DUAL:
+ switch (igniter) {
+ case ao_igniter_drogue:
+ AO_IGNITER_DROGUE = 1;
+ ao_delay(AO_IGNITER_FIRE_TIME);
+ AO_IGNITER_DROGUE = 0;
+ break;
+ case ao_igniter_main:
+ AO_IGNITER_MAIN = 1;
+ ao_delay(AO_IGNITER_FIRE_TIME);
+ AO_IGNITER_MAIN = 0;
+ break;
+ }
+ break;
+ case AO_IGNITE_MODE_APOGEE:
+ switch (igniter) {
+ case ao_igniter_drogue:
+ AO_IGNITER_DROGUE = 1;
+ ao_delay(AO_IGNITER_FIRE_TIME);
+ AO_IGNITER_DROGUE = 0;
+ ao_delay(AO_IGNITER_CHARGE_TIME);
+ AO_IGNITER_MAIN = 1;
+ ao_delay(AO_IGNITER_FIRE_TIME);
+ AO_IGNITER_MAIN = 0;
+ break;
+ }
+ break;
+ case AO_IGNITE_MODE_MAIN:
+ switch (igniter) {
+ case ao_igniter_main:
+ AO_IGNITER_DROGUE = 1;
+ ao_delay(AO_IGNITER_FIRE_TIME);
+ AO_IGNITER_DROGUE = 0;
+ ao_delay(AO_IGNITER_CHARGE_TIME);
+ AO_IGNITER_MAIN = 1;
+ ao_delay(AO_IGNITER_FIRE_TIME);
+ AO_IGNITER_MAIN = 0;
+ break;
+ }
+ break;
+ }
+ ao_ignition[igniter].firing = 0;
+}
+
+void
+ao_igniter(void)
+{
+ __xdata enum ao_ignter igniter;
+
+ ao_config_get();
+ for (;;) {
+ ao_sleep(&ao_ignition);
+ for (igniter = ao_igniter_drogue; igniter <= ao_igniter_main; igniter++) {
+ if (ao_ignition[igniter].request && !ao_ignition[igniter].fired) {
+ if (igniter == ao_igniter_drogue && ao_config.apogee_delay)
+ ao_delay(AO_SEC_TO_TICKS(ao_config.apogee_delay));
+
+ ao_igniter_fire(igniter);
+ ao_delay(AO_IGNITER_CHARGE_TIME);
+ ao_ignition[igniter].fired = 1;
+ }
+ }
+ }
+}
+
+void
+ao_ignite_manual(void)
+{
+ ao_cmd_white();
+ if (!ao_match_word("DoIt"))
+ return;
+ ao_cmd_white();
+ if (ao_cmd_lex_c == 'm') {
+ if(ao_match_word("main"))
+ ao_igniter_fire(ao_igniter_main);
+ } else {
+ if(ao_match_word("drogue"))
+ ao_igniter_fire(ao_igniter_drogue);
+ }
+}
+
+static __code char * __code igniter_status_names[] = {
+ "unknown", "ready", "active", "open"
+};
+
+void
+ao_ignite_print_status(enum ao_igniter igniter, __code char *name) __reentrant
+{
+ enum ao_igniter_status status = ao_igniter_status(igniter);
+ printf("Igniter: %6s Status: %s\n",
+ name,
+ igniter_status_names[status]);
+}
+
+void
+ao_ignite_test(void)
+{
+ ao_ignite_print_status(ao_igniter_drogue, "drogue");
+ ao_ignite_print_status(ao_igniter_main, "main");
+}
+
+__code struct ao_cmds ao_ignite_cmds[] = {
+ { ao_ignite_manual, "i <key> {main|drogue}\0Fire igniter. <key> is doit with D&I" },
+ { ao_ignite_test, "t\0Test igniter" },
+ { 0, NULL },
+};
+
+__xdata struct ao_task ao_igniter_task;
+
+void
+ao_ignite_set_pins(void)
+{
+ AO_IGNITER_DROGUE = 0;
+ AO_IGNITER_MAIN = 0;
+ AO_IGNITER_DIR |= AO_IGNITER_DROGUE_BIT | AO_IGNITER_MAIN_BIT;
+}
+
+void
+ao_igniter_init(void)
+{
+ ao_ignite_set_pins();
+ ao_cmd_register(&ao_ignite_cmds[0]);
+ ao_add_task(&ao_igniter_task, ao_igniter, "igniter");
+}
--- /dev/null
+/*
+ * Copyright © 2011 Anthony Towns <aj@erisian.com.au>
+ *
+ * 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 "cc1111.h"
+
+#define ENDOFCODE (CODESIZE)
+#define AO_INTFLASH_BLOCK 1024
+#define AO_INTFLASH_BLOCKS ((0x8000 - ENDOFCODE)/AO_INTFLASH_BLOCK)
+#define AO_INTFLASH_SIZE (AO_INTFLASH_BLOCK * AO_INTFLASH_BLOCKS)
+#define AO_INTFLASH_LOCATION (0x8000 - AO_INTFLASH_SIZE)
+
+/*
+ * 21000 * 24e6
+ * FWT = ------------
+ * 16e9
+ *
+ * = 31.5
+ *
+ * Round up and use 32
+ */
+
+#define FLASH_TIMING 0x20
+
+#if AO_INTFLASH_BLOCKS < 2
+#error "Too few pages"
+#endif
+
+#if AO_INFTLASH_LOCATION % 1024 != 0
+#error "Pages aren't aligned properly"
+#endif
+
+__xdata __at(AO_INTFLASH_LOCATION) uint8_t ao_intflash[AO_INTFLASH_SIZE];
+
+/* Total bytes of available storage */
+__pdata uint32_t ao_storage_total = sizeof(ao_intflash);
+
+/* Block size - device is erased in these units. */
+__pdata uint32_t ao_storage_block = AO_INTFLASH_BLOCK;
+
+/* Byte offset of config block. Will be ao_storage_block bytes long */
+__pdata uint32_t ao_storage_config = sizeof(ao_intflash) - AO_INTFLASH_BLOCK;
+
+/* Storage unit size - device reads and writes must be within blocks of this size. */
+__pdata uint16_t ao_storage_unit = AO_INTFLASH_BLOCK;
+
+__xdata static uint8_t ao_intflash_dma_done;
+static uint8_t ao_intflash_dma;
+
+/*
+ * The internal flash chip is arranged in 1kB sectors; the
+ * chip cannot erase in units smaller than that.
+ *
+ * Writing happens in units of 2 bytes and
+ * can only change bits from 1 to 0. So, you can rewrite
+ * the same contents, or append to an existing page easily enough
+ */
+
+/*
+ * Erase the specified sector
+ */
+uint8_t
+ao_storage_erase(uint32_t pos) __reentrant
+{
+ uint16_t addr;
+
+ if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total)
+ return 0;
+
+ addr = ((uint16_t)(ao_intflash + pos) >> 1);
+
+ FADDRH = addr >> 8;
+ FADDRL = addr;
+
+ __critical {
+ _asm
+ .even
+ orl _FCTL, #FCTL_ERASE; ; FCTL |= FCTL_ERASE
+ nop ; Required, see datasheet.
+ _endasm;
+ }
+
+ return 1;
+}
+
+/*
+ * Write to flash
+ */
+
+static void
+ao_intflash_write_aligned(uint16_t pos, __xdata void *d, uint16_t len) __reentrant
+{
+ pos = ((uint16_t) ao_intflash + pos) >> 1;
+
+ ao_dma_set_transfer(ao_intflash_dma,
+ d,
+ &FWDATAXADDR,
+ len,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_FLASH,
+ DMA_CFG1_SRCINC_1 |
+ DMA_CFG1_DESTINC_0 |
+ DMA_CFG1_PRIORITY_HIGH);
+
+ FADDRH = pos >> 8;
+ FADDRL = pos;
+
+ ao_dma_start(ao_intflash_dma);
+
+ __critical {
+ _asm
+ .even
+ orl _FCTL, #FCTL_WRITE; ; FCTL |= FCTL_WRITE
+ nop
+ _endasm;
+ }
+}
+
+static void
+ao_intflash_write_byte(uint16_t pos, uint8_t byte) __reentrant
+{
+ static __xdata uint8_t b[2];
+
+ if (pos & 1) {
+ b[0] = 0xff;
+ b[1] = byte;
+ } else {
+ b[0] = byte;
+ b[1] = 0xff;
+ }
+ ao_intflash_write_aligned(pos, b, 2);
+}
+
+uint8_t
+ao_storage_device_write(uint32_t pos32, __xdata void *v, uint16_t len) __reentrant
+{
+ uint16_t pos = pos32;
+ __xdata uint8_t *d = v;
+ uint8_t oddlen;
+
+ if (pos >= ao_storage_total || pos + len > ao_storage_total)
+ return 0;
+ if (len == 0)
+ return 1;
+
+ if (pos & 1) {
+ ao_intflash_write_byte(pos++, *d++);
+ len--;
+ }
+ oddlen = len & 1;
+ len -= oddlen;
+ if (len)
+ ao_intflash_write_aligned(pos, d, len);
+ if (oddlen)
+ ao_intflash_write_byte(pos + len, d[len]);
+
+ return 1;
+}
+
+/*
+ * Read from flash
+ */
+uint8_t
+ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
+{
+ if (pos >= ao_storage_total || pos + len > ao_storage_total)
+ return 0;
+ memcpy(d, ao_intflash+pos, len);
+ return 1;
+}
+
+void
+ao_storage_flush(void) __reentrant
+{
+}
+
+void
+ao_storage_setup(void)
+{
+}
+
+void
+ao_storage_device_info(void) __reentrant
+{
+ printf ("Using internal flash, starting at 0x%04x\n", AO_INTFLASH_LOCATION);
+}
+
+void
+ao_storage_device_init(void)
+{
+ ao_intflash_dma = ao_dma_alloc(&ao_intflash_dma_done);
+
+ FWT = FLASH_TIMING;
+}
--- /dev/null
+/*
+ * 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");
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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;
+
+void
+ao_led_on(uint8_t colors)
+{
+ P1 |= (colors & ao_led_enable);
+}
+
+void
+ao_led_off(uint8_t colors)
+{
+ P1 &= ~(colors & ao_led_enable);
+}
+
+void
+ao_led_set(uint8_t colors)
+{
+ P1 = (P1 & ~(ao_led_enable)) | (colors & ao_led_enable);
+}
+
+void
+ao_led_toggle(uint8_t colors)
+{
+ P1 ^= (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;
+ P1SEL &= ~enable;
+ P1 &= ~enable;
+ P1DIR |= enable;
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_packet_recv ao_rx_packet;
+__xdata struct ao_packet ao_tx_packet;
+__pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used;
+
+static __xdata char tx_data[AO_PACKET_MAX];
+static __xdata char rx_data[AO_PACKET_MAX];
+static __pdata uint8_t rx_seq;
+
+__xdata struct ao_task ao_packet_task;
+__xdata uint8_t ao_packet_enable;
+__xdata uint8_t ao_packet_master_sleeping;
+
+void
+ao_packet_send(void)
+{
+ ao_led_on(AO_LED_RED);
+ /* If any tx data is pending then copy it into the tx packet */
+ if (ao_packet_tx_used && ao_tx_packet.len == 0) {
+ memcpy(&ao_tx_packet.d, tx_data, ao_packet_tx_used);
+ ao_tx_packet.len = ao_packet_tx_used;
+ ao_tx_packet.seq++;
+ ao_packet_tx_used = 0;
+ ao_wakeup(&tx_data);
+ }
+ ao_radio_send(&ao_tx_packet, sizeof (ao_tx_packet));
+ ao_led_off(AO_LED_RED);
+}
+
+uint8_t
+ao_packet_recv(void)
+{
+ uint8_t dma_done;
+
+#ifdef AO_LED_GREEN
+ ao_led_on(AO_LED_GREEN);
+#endif
+ dma_done = ao_radio_recv(&ao_rx_packet, sizeof (struct ao_packet_recv));
+#ifdef AO_LED_GREEN
+ ao_led_off(AO_LED_GREEN);
+#endif
+
+ /* Check to see if we got a valid packet */
+ if (!dma_done)
+ return 0;
+ if (!(ao_rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK))
+ return 0;
+
+ /* SYN packets carry no data */
+ if (ao_rx_packet.packet.len == AO_PACKET_SYN) {
+ rx_seq = ao_rx_packet.packet.seq;
+ ao_tx_packet.seq = ao_rx_packet.packet.ack;
+ ao_tx_packet.ack = rx_seq;
+ } else if (ao_rx_packet.packet.len) {
+
+ /* Check for incoming data at the next sequence and
+ * for an empty data buffer
+ */
+ if (ao_rx_packet.packet.seq == (uint8_t) (rx_seq + (uint8_t) 1) &&
+ ao_packet_rx_used == ao_packet_rx_len) {
+
+ /* Copy data to the receive data buffer and set up the
+ * offsets
+ */
+ memcpy(rx_data, ao_rx_packet.packet.d, ao_rx_packet.packet.len);
+ ao_packet_rx_used = 0;
+ ao_packet_rx_len = ao_rx_packet.packet.len;
+
+ /* Mark the sequence that we've received to
+ * let the sender know when we return a packet
+ */
+ rx_seq = ao_rx_packet.packet.seq;
+ ao_tx_packet.ack = rx_seq;
+
+ /* Poke anyone looking for received data */
+ ao_wakeup(&ao_stdin_ready);
+ }
+ }
+
+ /* If the other side has seen the latest data we queued,
+ * wake up any task waiting to send data and let them go again
+ */
+ if (ao_rx_packet.packet.ack == ao_tx_packet.seq) {
+ ao_tx_packet.len = 0;
+ ao_wakeup(&ao_tx_packet);
+ }
+ return 1;
+}
+
+#ifndef PACKET_HAS_MASTER
+#define PACKET_HAS_MASTER 1
+#endif
+
+#if PACKET_HAS_MASTER
+void
+ao_packet_flush(void)
+{
+ /* If there is data to send, and this is the master,
+ * then poke the master to send all queued data
+ */
+ if (ao_packet_tx_used && ao_packet_master_sleeping)
+ ao_wakeup(&ao_packet_master_sleeping);
+}
+#endif /* PACKET_HAS_MASTER */
+
+void
+ao_packet_putchar(char c) __reentrant
+{
+ while (ao_packet_tx_used == AO_PACKET_MAX && ao_packet_enable) {
+#if PACKET_HAS_MASTER
+ ao_packet_flush();
+#endif
+ ao_sleep(&tx_data);
+ }
+
+ if (ao_packet_enable)
+ tx_data[ao_packet_tx_used++] = c;
+}
+
+char
+ao_packet_pollchar(void) __critical
+{
+ if (!ao_packet_enable)
+ return AO_READ_AGAIN;
+
+ if (ao_packet_rx_used == ao_packet_rx_len)
+ return AO_READ_AGAIN;
+
+ return rx_data[ao_packet_rx_used++];
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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 char
+ao_packet_getchar(void) __critical
+{
+ char c;
+ while ((c = ao_packet_pollchar()) == AO_READ_AGAIN) {
+ if (!ao_packet_enable)
+ break;
+ if (ao_packet_master_sleeping)
+ ao_wakeup(&ao_packet_master_sleeping);
+ flush();
+ ao_sleep(&ao_stdin_ready);
+ }
+ return c;
+}
+
+static void
+ao_packet_echo(void) __reentrant
+{
+ char c;
+ while (ao_packet_enable) {
+ c = ao_packet_getchar();
+ if (c != AO_READ_AGAIN)
+ putchar(c);
+ }
+ ao_exit();
+}
+
+static __xdata struct ao_task ao_packet_echo_task;
+static __xdata uint16_t ao_packet_master_delay;
+static __xdata uint16_t ao_packet_master_time;
+
+#define AO_PACKET_MASTER_DELAY_SHORT AO_MS_TO_TICKS(100)
+#define AO_PACKET_MASTER_DELAY_LONG AO_MS_TO_TICKS(1000)
+#define AO_PACKET_MASTER_DELAY_TIMEOUT AO_MS_TO_TICKS(2000)
+
+static void
+ao_packet_master_busy(void)
+{
+ ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT;
+ ao_packet_master_time = ao_time();
+}
+
+static void
+ao_packet_master_check_busy(void)
+{
+ int16_t idle;
+ if (ao_packet_master_delay != AO_PACKET_MASTER_DELAY_SHORT)
+ return;
+ idle = (int16_t) (ao_time() - ao_packet_master_time);
+
+ if (idle > AO_PACKET_MASTER_DELAY_TIMEOUT)
+ ao_packet_master_delay = AO_PACKET_MASTER_DELAY_LONG;
+}
+
+void
+ao_packet_master(void)
+{
+ ao_config_get();
+ ao_tx_packet.addr = ao_serial_number;
+ ao_tx_packet.len = AO_PACKET_SYN;
+ 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);
+ 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;
+ if (ao_rx_packet.packet.len)
+ ao_packet_master_busy();
+ 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;
+ }
+ }
+ ao_exit();
+}
+
+static void
+ao_packet_forward(void) __reentrant
+{
+ char c;
+ ao_packet_enable = 1;
+ ao_cmd_white();
+
+ flush();
+#if HAS_MONITOR
+ ao_set_monitor(0);
+#endif
+ ao_add_task(&ao_packet_task, ao_packet_master, "master");
+ ao_add_task(&ao_packet_echo_task, ao_packet_echo, "echo");
+ while ((c = getchar()) != '~') {
+ if (c == '\r') c = '\n';
+ ao_packet_putchar(c);
+ }
+
+ /* Wait for a second if there is any pending data */
+ for (c = 0; (ao_packet_tx_used || ao_tx_packet.len) && c < 10; c++)
+ ao_delay(AO_MS_TO_TICKS(100));
+ ao_packet_enable = 0;
+ while (ao_packet_echo_task.wchan || ao_packet_task.wchan) {
+ ao_radio_recv_abort();
+ ao_wakeup(&ao_stdin_ready);
+ ao_delay(AO_MS_TO_TICKS(10));
+ }
+}
+
+
+
+__code struct ao_cmds ao_packet_master_cmds[] = {
+ { ao_packet_forward, "p\0Remote packet link." },
+ { 0, NULL },
+};
+
+void
+ao_packet_master_init(void)
+{
+ ao_cmd_register(&ao_packet_master_cmds[0]);
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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
+ao_packet_slave(void)
+{
+ ao_tx_packet.addr = ao_serial_number;
+ ao_tx_packet.len = AO_PACKET_SYN;
+ while (ao_packet_enable) {
+ if (ao_packet_recv()) {
+ memcpy(&ao_tx_packet.callsign, &ao_rx_packet.packet.callsign, AO_MAX_CALLSIGN);
+#if HAS_FLIGHT
+ ao_flight_force_idle = TRUE;
+#endif
+ ao_packet_send();
+ }
+ }
+ ao_exit();
+}
+
+void
+ao_packet_slave_start(void)
+{
+ if (!ao_packet_enable) {
+ ao_packet_enable = 1;
+ ao_add_task(&ao_packet_task, ao_packet_slave, "slave");
+ }
+}
+
+void
+ao_packet_slave_stop(void)
+{
+ if (ao_packet_enable) {
+ ao_packet_enable = 0;
+ while (ao_packet_task.wchan) {
+ ao_radio_recv_abort();
+ ao_delay(AO_MS_TO_TICKS(10));
+ }
+ }
+}
+
+void
+ao_packet_slave_init(uint8_t enable)
+{
+ ao_add_stdio(ao_packet_pollchar,
+ ao_packet_putchar,
+ NULL);
+ if (enable)
+ ao_packet_slave_start();
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#if defined(TELEMETRUM_V_1_0)
+ #define HAS_FLIGHT 1
+ #define HAS_USB 1
+ #define HAS_BEEP 1
+ #define HAS_GPS 1
+ #define HAS_SERIAL_1 1
+ #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
+ #define DBG_ON_P0 0
+ #define IGNITE_ON_P2 1
+ #define IGNITE_ON_P0 0
+ #define PACKET_HAS_MASTER 0
+ #define PACKET_HAS_SLAVE 1
+
+ #define HAS_COMPANION 1
+ #define COMPANION_CS_ON_P1 1
+ #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */
+ #define COMPANION_CS P1_2
+
+ #define AO_LED_RED 1
+ #define LEDS_AVAILABLE (AO_LED_RED)
+ #define HAS_EXTERNAL_TEMP 0
+ #define HAS_ACCEL_REF 0
+ #define HAS_ACCEL 1
+ #define HAS_IGNITE 1
+ #define HAS_MONITOR 0
+#endif
+
+#if defined(TELEMETRUM_V_1_1)
+ #define HAS_FLIGHT 1
+ #define HAS_USB 1
+ #define HAS_BEEP 1
+ #define HAS_GPS 1
+ #define HAS_SERIAL_1 1
+ #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
+ #define DBG_ON_P0 0
+ #define IGNITE_ON_P2 1
+ #define IGNITE_ON_P0 0
+ #define PACKET_HAS_MASTER 0
+ #define PACKET_HAS_SLAVE 1
+
+ #define HAS_COMPANION 1
+ #define COMPANION_CS_ON_P1 1
+ #define COMPANION_CS_MASK 0x4 /* CS1 is P1_2 */
+ #define COMPANION_CS P1_2
+
+ #define AO_LED_RED 1
+ #define LEDS_AVAILABLE (AO_LED_RED)
+ #define HAS_EXTERNAL_TEMP 0
+ #define HAS_ACCEL_REF 1
+ #define SPI_CS_ON_P1 1
+ #define SPI_CS_ON_P0 0
+ #define M25_CS_MASK 0x02 /* CS0 is P1_1 */
+ #define M25_MAX_CHIPS 1
+ #define HAS_ACCEL 1
+ #define HAS_IGNITE 1
+ #define HAS_MONITOR 0
+#endif
+
+#if defined(TELEDONGLE_V_0_2)
+ #define HAS_FLIGHT 0
+ #define HAS_USB 1
+ #define HAS_BEEP 0
+ #define HAS_SERIAL_1 0
+ #define USE_SERIAL_STDIN 0
+ #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
+ #define IGNITE_ON_P0 0
+ #define PACKET_HAS_MASTER 1
+ #define PACKET_HAS_SLAVE 0
+ #define AO_LED_RED 1
+ #define AO_LED_GREEN 2
+ #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN)
+ #define SPI_CS_ON_P1 1
+ #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)
+ #define HAS_FLIGHT 1
+ #define HAS_USB 0
+ #define HAS_BEEP 0
+ #define HAS_GPS 0
+ #define HAS_SERIAL_1 0
+ #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
+ #define IGNITE_ON_P0 1
+ #define PACKET_HAS_MASTER 0
+ #define PACKET_HAS_SLAVE 1
+ #define USE_FAST_ASCENT_LOG 1
+
+ #define AO_LED_GREEN 1
+ #define AO_LED_RED 2
+ #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN)
+ #define HAS_EXTERNAL_TEMP 0
+ #define HAS_ACCEL 0
+ #define HAS_IGNITE 1
+ #define HAS_MONITOR 0
+#endif
+
+#if defined(TELENANO_V_0_1)
+ #define HAS_FLIGHT 1
+ #define HAS_USB 0
+ #define HAS_BEEP 0
+ #define HAS_GPS 0
+ #define HAS_SERIAL_1 0
+ #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
+ #define IGNITE_ON_P0 1
+ #define PACKET_HAS_MASTER 0
+ #define PACKET_HAS_SLAVE 1
+
+ #define AO_LED_GREEN 1
+ #define AO_LED_RED 2
+ #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN)
+ #define HAS_EXTERNAL_TEMP 0
+ #define HAS_ACCEL 0
+ #define HAS_IGNITE 0
+ #define HAS_MONITOR 0
+#endif
+
+#if defined(TELEMETRUM_V_0_1)
+ #define HAS_FLIGHT 1
+ #define HAS_USB 1
+ #define HAS_BEEP 1
+ #define HAS_GPS 1
+ #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 1
+ #define USE_INTERNAL_FLASH 0
+ #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 1
+ #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 1
+ #define HAS_IGNITE 1
+ #define HAS_MONITOR 0
+#endif
+
+#if defined(TELEDONGLE_V_0_1)
+ #define HAS_FLIGHT 0
+ #define HAS_USB 1
+ #define HAS_BEEP 0
+ #define HAS_SERIAL_1 0
+ #define USE_SERIAL_STDIN 0
+ #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
+ #define IGNITE_ON_P0 0
+ #define PACKET_HAS_MASTER 1
+ #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 SPI_CS_ON_P1 0
+ #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)
+ #define HAS_FLIGHT 0
+ #define HAS_USB 1
+ #define HAS_BEEP 0
+ #define HAS_SERIAL_1 0
+ #define USE_SERIAL_STDIN 0
+ #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
+ #define IGNITE_ON_P0 0
+ #define PACKET_HAS_MASTER 1
+ #define PACKET_HAS_SLAVE 0
+ #define AO_LED_RED 2
+ #define LEDS_AVAILABLE (AO_LED_RED)
+ #define SPI_CS_ON_P1 0
+ #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)
+ #define HAS_FLIGHT 0
+ #define HAS_USB 1
+ #define HAS_BEEP 0
+ #define HAS_SERIAL_1 1
+ #define USE_SERIAL_STDIN 1
+ #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
+ #define IGNITE_ON_P2 0
+ #define IGNITE_ON_P0 0
+ #define PACKET_HAS_MASTER 1
+ #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 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)
+ #define HAS_FLIGHT 0
+ #define HAS_USB 1
+ #define HAS_BEEP 1
+ #define HAS_SERIAL_1 1
+ #define HAS_SERIAL_1_ALT_1 1
+ #define HAS_SERIAL_1_ALT_2 0
+ #define HAS_SERIAL_1_HW_FLOW 1
+ #define USE_SERIAL_STDIN 1
+ #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
+ #define DBG_ON_P0 0
+ #define IGNITE_ON_P2 0
+ #define IGNITE_ON_P0 0
+ #define PACKET_HAS_MASTER 1
+ #define PACKET_HAS_SLAVE 0
+ #define AO_LED_RED 1
+ #define AO_LED_GREEN 2
+ #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN)
+ #define SPI_CS_ON_P1 1
+ #define SPI_CS_ON_P0 0
+ #define M25_CS_MASK 0x04 /* CS0 is P1_2 */
+ #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
+
+ #define DBG_CLOCK (1 << 4) /* mi0 */
+ #define DBG_DATA (1 << 5) /* mo0 */
+ #define DBG_RESET_N (1 << 3) /* c0 */
+
+ #define DBG_CLOCK_PIN (P1_4)
+ #define DBG_DATA_PIN (P1_5)
+ #define DBG_RESET_N_PIN (P1_3)
+
+ #define DBG_PORT_NUM 1
+ #define DBG_PORT P1
+ #define DBG_PORT_SEL P1SEL
+ #define DBG_PORT_INP P1INP
+ #define DBG_PORT_DIR P1DIR
+
+#endif /* DBG_ON_P1 */
+
+#if DBG_ON_P0
+
+ #define DBG_CLOCK (1 << 3)
+ #define DBG_DATA (1 << 4)
+ #define DBG_RESET_N (1 << 5)
+
+ #define DBG_CLOCK_PIN (P0_3)
+ #define DBG_DATA_PIN (P0_4)
+ #define DBG_RESET_N_PIN (P0_5)
+
+ #define DBG_PORT_NUM 0
+ #define DBG_PORT P0
+ #define DBG_PORT_SEL P0SEL
+ #define DBG_PORT_INP P0INP
+ #define DBG_PORT_DIR P0DIR
+
+#endif /* DBG_ON_P0 */
+
+#if COMPANION_CS_ON_P1
+ #define COMPANION_CS_PORT P1
+ #define COMPANION_CS_SEL P1SEL
+ #define COMPANION_CS_DIR P1DIR
+#endif
+
+#if SPI_CS_ON_P1
+ #define SPI_CS_PORT P1
+ #define SPI_CS_SEL P1SEL
+ #define SPI_CS_DIR P1DIR
+#endif
+
+#if SPI_CS_ON_P0
+ #define SPI_CS_PORT P0
+ #define SPI_CS_SEL P0SEL
+ #define SPI_CS_DIR P0DIR
+#endif
+
+#ifndef IGNITE_ON_P2
+#error Please define IGNITE_ON_P2
+#endif
+
+#ifndef IGNITE_ON_P0
+#error Please define IGNITE_ON_P0
+#endif
+
+#ifndef HAS_SERIAL_1
+#error Please define HAS_SERIAL_1
+#endif
+
+#ifndef USE_SERIAL_STDIN
+#error Please define USE_SERIAL_STDIN
+#endif
+
+#ifndef HAS_ADC
+#error Please define HAS_ADC
+#endif
+
+#ifndef HAS_EEPROM
+#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
+#endif
+#endif
+
+#ifndef HAS_DBG
+#error Please define HAS_DBG
+#endif
+
+#ifndef HAS_IGNITE
+#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
+
+#ifndef PACKET_HAS_SLAVE
+#error Please define PACKET_HAS_SLAVE
+#endif
+
+#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_ */
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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"
+
+/* Values from SmartRF® Studio for:
+ *
+ * Deviation: 20.507812 kHz
+ * Datarate: 38.360596 kBaud
+ * Modulation: GFSK
+ * RF Freq: 434.549927 MHz
+ * Channel: 99.975586 kHz
+ * Channel: 0
+ * RX filter: 93.75 kHz
+ */
+
+/*
+ * For IF freq of 140.62kHz, the IF value is:
+ *
+ * 140.62e3 / (24e6 / 2**10) = 6
+ */
+
+#define IF_FREQ_CONTROL 6
+
+/*
+ * For channel bandwidth of 93.75 kHz, the CHANBW_E and CHANBW_M values are
+ *
+ * BW = 24e6 / (8 * (4 + M) * 2 ** E)
+ *
+ * So, M = 0 and E = 3
+ */
+
+#define CHANBW_M 0
+#define CHANBW_E 3
+
+/*
+ * For a symbol rate of 38360kBaud, the DRATE_E and DRATE_M values are:
+ *
+ * R = (256 + M) * 2** E * 24e6 / 2**28
+ *
+ * So M is 163 and E is 10
+ */
+
+#define DRATE_E 10
+#define DRATE_M 163
+
+/*
+ * For a channel deviation of 20.5kHz, the DEVIATION_E and DEVIATION_M values are:
+ *
+ * F = 24e6/2**17 * (8 + DEVIATION_M) * 2**DEVIATION_E
+ *
+ * So M is 6 and E is 3
+ */
+
+#define DEVIATION_M 6
+#define DEVIATION_E 3
+
+/*
+ * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone),
+ * so the DRATE_E and DRATE_M values are:
+ *
+ * M is 94 and E is 6
+ *
+ * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes
+ */
+
+#define RDF_DRATE_E 6
+#define RDF_DRATE_M 94
+#define RDF_PACKET_LEN 50
+
+/*
+ * RDF deviation should match the normal NFM value of 5kHz
+ *
+ * M is 6 and E is 1
+ *
+ */
+
+#define RDF_DEVIATION_M 6
+#define RDF_DEVIATION_E 1
+
+/* This are from the table for 433MHz */
+
+#define RF_POWER_M30_DBM 0x12
+#define RF_POWER_M20_DBM 0x0e
+#define RF_POWER_M15_DBM 0x1d
+#define RF_POWER_M10_DBM 0x34
+#define RF_POWER_M5_DBM 0x2c
+#define RF_POWER_0_DBM 0x60
+#define RF_POWER_5_DBM 0x84
+#define RF_POWER_7_DBM 0xc8
+#define RF_POWER_10_DBM 0xc0
+
+#define RF_POWER RF_POWER_10_DBM
+
+static __code uint8_t radio_setup[] = {
+ RF_PA_TABLE7_OFF, RF_POWER,
+ RF_PA_TABLE6_OFF, RF_POWER,
+ RF_PA_TABLE5_OFF, RF_POWER,
+ RF_PA_TABLE4_OFF, RF_POWER,
+ RF_PA_TABLE3_OFF, RF_POWER,
+ RF_PA_TABLE2_OFF, RF_POWER,
+ RF_PA_TABLE1_OFF, RF_POWER,
+ RF_PA_TABLE0_OFF, RF_POWER,
+
+ RF_FSCTRL1_OFF, (IF_FREQ_CONTROL << RF_FSCTRL1_FREQ_IF_SHIFT),
+ RF_FSCTRL0_OFF, (0 << RF_FSCTRL0_FREQOFF_SHIFT),
+
+ RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
+ (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) |
+ (DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)),
+ RF_MDMCFG3_OFF, (DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT),
+ RF_MDMCFG2_OFF, (RF_MDMCFG2_DEM_DCFILT_OFF |
+ RF_MDMCFG2_MOD_FORMAT_GFSK |
+ RF_MDMCFG2_SYNC_MODE_15_16_THRES),
+ RF_MDMCFG1_OFF, (RF_MDMCFG1_FEC_EN |
+ RF_MDMCFG1_NUM_PREAMBLE_4 |
+ (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)),
+ RF_MDMCFG0_OFF, (17 << RF_MDMCFG0_CHANSPC_M_SHIFT),
+
+ RF_CHANNR_OFF, 0,
+
+ RF_DEVIATN_OFF, ((DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) |
+ (DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)),
+
+ /* SmartRF says set LODIV_BUF_CURRENT_TX to 0
+ * And, we're not using power ramping, so use PA_POWER 0
+ */
+ RF_FREND0_OFF, ((1 << RF_FREND0_LODIV_BUF_CURRENT_TX_SHIFT) |
+ (0 << RF_FREND0_PA_POWER_SHIFT)),
+
+ RF_FREND1_OFF, ((1 << RF_FREND1_LNA_CURRENT_SHIFT) |
+ (1 << RF_FREND1_LNA2MIX_CURRENT_SHIFT) |
+ (1 << RF_FREND1_LODIV_BUF_CURRENT_RX_SHIFT) |
+ (2 << RF_FREND1_MIX_CURRENT_SHIFT)),
+
+ RF_FSCAL3_OFF, 0xE9,
+ RF_FSCAL2_OFF, 0x0A,
+ RF_FSCAL1_OFF, 0x00,
+ RF_FSCAL0_OFF, 0x1F,
+
+ RF_TEST2_OFF, 0x88,
+ RF_TEST1_OFF, 0x31,
+ RF_TEST0_OFF, 0x09,
+
+ /* default sync values */
+ RF_SYNC1_OFF, 0xD3,
+ RF_SYNC0_OFF, 0x91,
+
+ /* max packet length */
+ RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)|
+ PKTCTRL1_APPEND_STATUS|
+ PKTCTRL1_ADR_CHK_NONE),
+ RF_PKTCTRL0_OFF, (RF_PKTCTRL0_WHITE_DATA|
+ RF_PKTCTRL0_PKT_FORMAT_NORMAL|
+ RF_PKTCTRL0_CRC_EN|
+ RF_PKTCTRL0_LENGTH_CONFIG_FIXED),
+ RF_ADDR_OFF, 0x00,
+ RF_MCSM2_OFF, (RF_MCSM2_RX_TIME_END_OF_PACKET),
+ RF_MCSM1_OFF, (RF_MCSM1_CCA_MODE_RSSI_BELOW_UNLESS_RECEIVING|
+ RF_MCSM1_RXOFF_MODE_IDLE|
+ RF_MCSM1_TXOFF_MODE_IDLE),
+ RF_MCSM0_OFF, (RF_MCSM0_FS_AUTOCAL_FROM_IDLE|
+ RF_MCSM0_MAGIC_3|
+ RF_MCSM0_CLOSE_IN_RX_0DB),
+ RF_FOCCFG_OFF, (RF_FOCCFG_FOC_PRE_K_3K,
+ RF_FOCCFG_FOC_POST_K_PRE_K,
+ RF_FOCCFG_FOC_LIMIT_BW_OVER_4),
+ RF_BSCFG_OFF, (RF_BSCFG_BS_PRE_K_2K|
+ RF_BSCFG_BS_PRE_KP_3KP|
+ RF_BSCFG_BS_POST_KI_PRE_KI|
+ RF_BSCFG_BS_POST_KP_PRE_KP|
+ RF_BSCFG_BS_LIMIT_0),
+ RF_AGCCTRL2_OFF, 0x43,
+ RF_AGCCTRL1_OFF, 0x40,
+ RF_AGCCTRL0_OFF, 0x91,
+
+ RF_IOCFG2_OFF, 0x00,
+ RF_IOCFG1_OFF, 0x00,
+ RF_IOCFG0_OFF, 0x00,
+};
+
+static __code uint8_t rdf_setup[] = {
+ RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
+ (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) |
+ (RDF_DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)),
+ RF_MDMCFG3_OFF, (RDF_DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT),
+ RF_MDMCFG2_OFF, (RF_MDMCFG2_DEM_DCFILT_OFF |
+ RF_MDMCFG2_MOD_FORMAT_GFSK |
+ RF_MDMCFG2_SYNC_MODE_15_16_THRES),
+ RF_MDMCFG1_OFF, (RF_MDMCFG1_FEC_DIS |
+ RF_MDMCFG1_NUM_PREAMBLE_2 |
+ (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)),
+
+ RF_DEVIATN_OFF, ((RDF_DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) |
+ (RDF_DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)),
+
+ /* packet length is set in-line */
+ RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)|
+ PKTCTRL1_ADR_CHK_NONE),
+ RF_PKTCTRL0_OFF, (RF_PKTCTRL0_PKT_FORMAT_NORMAL|
+ RF_PKTCTRL0_LENGTH_CONFIG_FIXED),
+};
+
+static __code uint8_t fixed_pkt_setup[] = {
+ RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
+ (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) |
+ (DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)),
+ RF_MDMCFG3_OFF, (DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT),
+ RF_MDMCFG2_OFF, (RF_MDMCFG2_DEM_DCFILT_OFF |
+ RF_MDMCFG2_MOD_FORMAT_GFSK |
+ RF_MDMCFG2_SYNC_MODE_15_16_THRES),
+ RF_MDMCFG1_OFF, (RF_MDMCFG1_FEC_EN |
+ RF_MDMCFG1_NUM_PREAMBLE_4 |
+ (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)),
+
+ RF_DEVIATN_OFF, ((DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) |
+ (DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)),
+
+ /* max packet length -- now set inline */
+ RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)|
+ PKTCTRL1_APPEND_STATUS|
+ PKTCTRL1_ADR_CHK_NONE),
+ RF_PKTCTRL0_OFF, (RF_PKTCTRL0_WHITE_DATA|
+ RF_PKTCTRL0_PKT_FORMAT_NORMAL|
+ RF_PKTCTRL0_CRC_EN|
+ RF_PKTCTRL0_LENGTH_CONFIG_FIXED),
+};
+
+__xdata uint8_t ao_radio_dma;
+__xdata uint8_t ao_radio_dma_done;
+__xdata uint8_t ao_radio_done;
+__xdata uint8_t ao_radio_abort;
+__xdata uint8_t ao_radio_mutex;
+
+void
+ao_radio_general_isr(void) __interrupt 16
+{
+ S1CON &= ~0x03;
+ if (RFIF & RFIF_IM_TIMEOUT) {
+ ao_radio_recv_abort();
+ RFIF &= ~ RFIF_IM_TIMEOUT;
+ } else if (RFIF & RFIF_IM_DONE) {
+ ao_radio_done = 1;
+ ao_wakeup(&ao_radio_done);
+ RFIF &= ~RFIF_IM_DONE;
+ }
+}
+
+void
+ao_radio_set_packet(void)
+{
+ uint8_t i;
+ for (i = 0; i < sizeof (fixed_pkt_setup); i += 2)
+ RF[fixed_pkt_setup[i]] = fixed_pkt_setup[i+1];
+}
+
+void
+ao_radio_idle(void)
+{
+ if (RF_MARCSTATE != RF_MARCSTATE_IDLE)
+ {
+ do {
+ RFST = RFST_SIDLE;
+ ao_yield();
+ } while (RF_MARCSTATE != RF_MARCSTATE_IDLE);
+ }
+}
+
+void
+ao_radio_get(uint8_t len)
+{
+ ao_config_get();
+ ao_mutex_get(&ao_radio_mutex);
+ ao_radio_idle();
+ RF_CHANNR = ao_config.radio_channel;
+ RF_FREQ2 = (uint8_t) (ao_config.radio_setting >> 16);
+ RF_FREQ1 = (uint8_t) (ao_config.radio_setting >> 8);
+ RF_FREQ0 = (uint8_t) (ao_config.radio_setting);
+ RF_PKTLEN = len;
+}
+
+
+void
+ao_radio_send(__xdata void *packet, uint8_t size) __reentrant
+{
+ ao_radio_get(size);
+ ao_radio_done = 0;
+ ao_dma_set_transfer(ao_radio_dma,
+ packet,
+ &RFDXADDR,
+ size,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_RADIO,
+ DMA_CFG1_SRCINC_1 |
+ DMA_CFG1_DESTINC_0 |
+ DMA_CFG1_PRIORITY_HIGH);
+ ao_dma_start(ao_radio_dma);
+ RFST = RFST_STX;
+ __critical while (!ao_radio_done)
+ ao_sleep(&ao_radio_done);
+ ao_radio_put();
+}
+
+uint8_t
+ao_radio_recv(__xdata void *packet, uint8_t size) __reentrant
+{
+ ao_radio_abort = 0;
+ ao_radio_get(size - 2);
+ ao_dma_set_transfer(ao_radio_dma,
+ &RFDXADDR,
+ packet,
+ size,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_RADIO,
+ DMA_CFG1_SRCINC_0 |
+ DMA_CFG1_DESTINC_1 |
+ DMA_CFG1_PRIORITY_HIGH);
+ ao_dma_start(ao_radio_dma);
+ RFST = RFST_SRX;
+
+ /* Wait for DMA to be done, for the radio receive process to
+ * get aborted or for a receive timeout to fire
+ */
+ __critical while (!ao_radio_dma_done && !ao_radio_abort)
+ if (ao_sleep(&ao_radio_dma_done))
+ break;
+
+ /* If recv was aborted, clean up by stopping the DMA engine
+ * and idling the radio
+ */
+ if (!ao_radio_dma_done) {
+ ao_dma_abort(ao_radio_dma);
+ ao_radio_idle();
+ }
+ ao_radio_put();
+ return ao_radio_dma_done;
+}
+
+/*
+ * Wake up a task waiting to receive a radio packet
+ * and tell them to abort the transfer
+ */
+
+void
+ao_radio_recv_abort(void)
+{
+ ao_radio_abort = 1;
+ ao_wakeup(&ao_radio_dma_done);
+}
+
+__xdata ao_radio_rdf_value = 0x55;
+
+void
+ao_radio_rdf(uint8_t pkt_len)
+{
+ uint8_t i;
+
+ ao_radio_abort = 0;
+ ao_radio_get(pkt_len);
+ ao_radio_done = 0;
+ for (i = 0; i < sizeof (rdf_setup); i += 2)
+ RF[rdf_setup[i]] = rdf_setup[i+1];
+
+ ao_dma_set_transfer(ao_radio_dma,
+ &ao_radio_rdf_value,
+ &RFDXADDR,
+ pkt_len,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_RADIO,
+ DMA_CFG1_SRCINC_0 |
+ DMA_CFG1_DESTINC_0 |
+ DMA_CFG1_PRIORITY_HIGH);
+ ao_dma_start(ao_radio_dma);
+ RFST = RFST_STX;
+ __critical while (!ao_radio_done && !ao_radio_abort)
+ ao_sleep(&ao_radio_done);
+ if (!ao_radio_done) {
+ ao_dma_abort(ao_radio_dma);
+ ao_radio_idle();
+ }
+ ao_radio_set_packet();
+ ao_radio_put();
+}
+
+void
+ao_radio_rdf_abort(void)
+{
+ ao_radio_abort = 1;
+ ao_wakeup(&ao_radio_done);
+}
+
+
+/* Output carrier */
+void
+ao_radio_test(void)
+{
+ uint8_t mode = 2;
+ static __xdata radio_on;
+ ao_cmd_white();
+ if (ao_cmd_lex_c != '\n') {
+ ao_cmd_decimal();
+ mode = (uint8_t) ao_cmd_lex_u32;
+ }
+ mode++;
+ if ((mode & 2) && !radio_on) {
+#if HAS_MONITOR
+ ao_set_monitor(0);
+#endif
+#if PACKET_HAS_SLAVE
+ ao_packet_slave_stop();
+#endif
+ ao_radio_get(0xff);
+ RFST = RFST_STX;
+ radio_on = 1;
+ }
+ if (mode == 3) {
+ printf ("Hit a character to stop..."); flush();
+ getchar();
+ putchar('\n');
+ }
+ if ((mode & 1) && radio_on) {
+ ao_radio_idle();
+ ao_radio_put();
+ radio_on = 0;
+ }
+}
+
+__code struct ao_cmds ao_radio_cmds[] = {
+ { ao_radio_test, "C <1 start, 0 stop, none both>\0Radio carrier test" },
+ { 0, NULL },
+};
+
+void
+ao_radio_init(void)
+{
+ uint8_t i;
+ for (i = 0; i < sizeof (radio_setup); i += 2)
+ RF[radio_setup[i]] = radio_setup[i+1];
+ ao_radio_set_packet();
+ ao_radio_dma_done = 1;
+ ao_radio_dma = ao_dma_alloc(&ao_radio_dma_done);
+ RFIF = 0;
+ RFIM = RFIM_IM_TIMEOUT|RFIM_IM_DONE;
+ IEN2 |= IEN2_RFIE;
+ ao_cmd_register(&ao_radio_cmds[0]);
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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"
+
+/* Use the watchdog timer to force a complete reboot
+ */
+void
+ao_reboot(void)
+{
+ WDCTL = WDCTL_EN | WDCTL_MODE_WATCHDOG | WDCTL_INT_32768;
+ ao_delay(AO_SEC_TO_TICKS(2));
+ ao_panic(AO_PANIC_REBOOT);
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+#include "ao.h"
+
+__code __at (0x00a0) uint16_t ao_romconfig_version = AO_ROMCONFIG_VERSION;
+__code __at (0x00a2) uint16_t ao_romconfig_check = ~AO_ROMCONFIG_VERSION;
+__code __at (0x00a4) uint16_t ao_serial_number = 0;
+/*
+ * For 434.550MHz, the frequency value is:
+ *
+ * 434.550e6 / (24e6 / 2**16) = 1186611.2
+ *
+ * This value is stored in a const variable so that
+ * ao-load can change it during programming for
+ * devices that have no eeprom for config data.
+ */
+__code __at (0x00a6) uint32_t ao_radio_cal = 1186611;
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_fifo ao_usart1_rx_fifo;
+volatile __xdata struct ao_fifo ao_usart1_tx_fifo;
+
+void
+ao_serial_rx1_isr(void) __interrupt 3
+{
+ if (!ao_fifo_full(ao_usart1_rx_fifo))
+ ao_fifo_insert(ao_usart1_rx_fifo, U1DBUF);
+ 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, U1DBUF);
+ }
+}
+
+void
+ao_serial_tx1_isr(void) __interrupt 14
+{
+ UTX1IF = 0;
+ ao_serial_tx1_started = 0;
+ ao_serial_tx1_start();
+ ao_wakeup(&ao_usart1_tx_fifo);
+}
+
+char
+ao_serial_getchar(void) __critical
+{
+ char c;
+ while (ao_fifo_empty(ao_usart1_rx_fifo))
+ ao_sleep(&ao_usart1_rx_fifo);
+ ao_fifo_remove(ao_usart1_rx_fifo, c);
+ return c;
+}
+
+#if USE_SERIAL_STDIN
+char
+ao_serial_pollchar(void) __critical
+{
+ char c;
+ if (ao_fifo_empty(ao_usart1_rx_fifo))
+ return AO_READ_AGAIN;
+ ao_fifo_remove(ao_usart1_rx_fifo,c);
+ return c;
+}
+#endif
+
+void
+ao_serial_putchar(char c) __critical
+{
+ 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();
+}
+
+void
+ao_serial_drain(void) __critical
+{
+ while (!ao_fifo_empty(ao_usart1_tx_fifo))
+ ao_sleep(&ao_usart1_tx_fifo);
+}
+
+static __code struct {
+ uint8_t baud;
+ uint8_t gcr;
+} ao_serial_speeds[] = {
+ /* [AO_SERIAL_SPEED_4800] = */ {
+ /* .baud = */ 163,
+ /* .gcr = */ (7 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
+ },
+ /* [AO_SERIAL_SPEED_9600] = */ {
+ /* .baud = */ 163,
+ /* .gcr = */ (8 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
+ },
+ /* [AO_SERIAL_SPEED_19200] = */ {
+ /* .baud = */ 163,
+ /* .gcr = */ (9 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
+ },
+ /* [AO_SERIAL_SPEED_57600] = */ {
+ /* .baud = */ 59,
+ /* .gcr = */ (11 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
+ },
+};
+
+void
+ao_serial_set_speed(uint8_t speed)
+{
+ ao_serial_drain();
+ if (speed > AO_SERIAL_SPEED_57600)
+ return;
+ U1UCR |= UxUCR_FLUSH;
+ U1BAUD = ao_serial_speeds[speed].baud;
+ U1GCR = ao_serial_speeds[speed].gcr;
+}
+
+void
+ao_serial_init(void)
+{
+#if HAS_SERIAL_1_ALT_1
+ /* Set up the USART pin assignment */
+ PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_1;
+
+ P2DIR = (P2DIR & ~P2DIR_PRIP0_MASK) | P2DIR_PRIP0_USART1_USART0;
+
+ /* Make the USART pins be controlled by the USART */
+ P0SEL |= (1 << 5) | (1 << 4);
+#if HAS_SERIAL_1_HW_FLOW
+ P0SEL |= (1 << 3) | (1 << 2);
+#endif
+#else
+ /* Set up the USART pin assignment */
+ PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_2;
+
+ P2SEL = (P2SEL & ~(P2SEL_PRI3P1_MASK | P2SEL_PRI2P1_MASK)) |
+ (P2SEL_PRI3P1_USART1 | P2SEL_PRI2P1_USART1);
+
+ /* Make the USART pins be controlled by the USART */
+ P1SEL |= (1 << 6) | (1 << 7);
+ P1SEL |= (1 << 5) | (1 << 4);
+#endif
+
+ /* UART mode with receiver enabled */
+ U1CSR = (UxCSR_MODE_UART | UxCSR_RE);
+
+ /* Pick a 4800 baud rate */
+ ao_serial_set_speed(AO_SERIAL_SPEED_4800);
+
+ /* Reasonable serial parameters */
+ U1UCR = (UxUCR_FLUSH |
+#if HAS_SERIAL_1_HW_FLOW
+ UxUCR_FLOW_ENABLE |
+#else
+ UxUCR_FLOW_DISABLE |
+#endif
+ UxUCR_D9_EVEN_PARITY |
+ UxUCR_BIT9_8_BITS |
+ UxUCR_PARITY_DISABLE |
+ UxUCR_SPB_1_STOP_BIT |
+ UxUCR_STOP_HIGH |
+ UxUCR_START_LOW);
+
+ IEN0 |= IEN0_URX1IE;
+ IEN2 |= IEN2_UTX1IE;
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+#include "ao.h"
+
+/* Shared mutex to protect SPI bus, must cover the entire
+ * operation, from CS low to CS high. This means that any SPI
+ * user must protect the SPI bus with this mutex
+ */
+__xdata uint8_t ao_spi_mutex;
+__xdata uint8_t ao_spi_dma_in_done;
+__xdata uint8_t ao_spi_dma_out_done;
+
+uint8_t ao_spi_dma_out_id;
+uint8_t ao_spi_dma_in_id;
+
+static __xdata uint8_t ao_spi_const = 0xff;
+
+/* Send bytes over SPI.
+ *
+ * This sets up two DMA engines, one writing the data and another reading
+ * bytes coming back. We use the bytes coming back to tell when the transfer
+ * is complete, as the transmit register is double buffered and hence signals
+ * completion one byte before the transfer is actually complete
+ */
+void
+ao_spi_send(void __xdata *block, uint16_t len) __reentrant
+{
+ ao_dma_set_transfer(ao_spi_dma_in_id,
+ &U0DBUFXADDR,
+ &ao_spi_const,
+ len,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_URX0,
+ DMA_CFG1_SRCINC_0 |
+ DMA_CFG1_DESTINC_0 |
+ DMA_CFG1_PRIORITY_NORMAL);
+
+ ao_dma_set_transfer(ao_spi_dma_out_id,
+ block,
+ &U0DBUFXADDR,
+ len,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_UTX0,
+ DMA_CFG1_SRCINC_1 |
+ DMA_CFG1_DESTINC_0 |
+ DMA_CFG1_PRIORITY_NORMAL);
+
+ ao_dma_start(ao_spi_dma_in_id);
+ ao_dma_start(ao_spi_dma_out_id);
+ ao_dma_trigger(ao_spi_dma_out_id);
+ __critical while (!ao_spi_dma_in_done)
+ ao_sleep(&ao_spi_dma_in_done);
+}
+
+/* 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
+{
+ ao_dma_set_transfer(ao_spi_dma_in_id,
+ &U0DBUFXADDR,
+ block,
+ len,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_URX0,
+ DMA_CFG1_SRCINC_0 |
+ DMA_CFG1_DESTINC_1 |
+ DMA_CFG1_PRIORITY_NORMAL);
+
+ ao_dma_set_transfer(ao_spi_dma_out_id,
+ &ao_spi_const,
+ &U0DBUFXADDR,
+ len,
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_UTX0,
+ DMA_CFG1_SRCINC_0 |
+ DMA_CFG1_DESTINC_0 |
+ DMA_CFG1_PRIORITY_NORMAL);
+
+ ao_dma_start(ao_spi_dma_in_id);
+ ao_dma_start(ao_spi_dma_out_id);
+ ao_dma_trigger(ao_spi_dma_out_id);
+ __critical while (!ao_spi_dma_in_done)
+ ao_sleep(&ao_spi_dma_in_done);
+}
+
+/*
+ * 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
+ */
+
+void
+ao_spi_init(void)
+{
+ /* Set up the USART pin assignment */
+ PERCFG = (PERCFG & ~PERCFG_U0CFG_ALT_MASK) | PERCFG_U0CFG_ALT_2;
+
+ /* Ensure that USART0 takes precidence over USART1 for pins that
+ * they share
+ */
+ P2SEL = (P2SEL & ~P2SEL_PRI3P1_MASK) | P2SEL_PRI3P1_USART0;
+
+ /* Make the SPI pins be controlled by the USART peripheral */
+ P1SEL |= ((1 << 5) | (1 << 4) | (1 << 3));
+
+ /* Set up OUT DMA */
+ ao_spi_dma_out_id = ao_dma_alloc(&ao_spi_dma_out_done);
+
+ /* Set up IN DMA */
+ ao_spi_dma_in_id = ao_dma_alloc(&ao_spi_dma_in_done);
+
+ /* Set up the USART.
+ *
+ * SPI master mode
+ */
+ U0CSR = (UxCSR_MODE_SPI | UxCSR_RE | UxCSR_MASTER);
+
+ /* Set the baud rate and signal parameters
+ *
+ * The cc1111 is limited to a 24/8 MHz SPI clock.
+ * Every peripheral I've ever seen goes faster than that,
+ * so set the clock to 3MHz (BAUD_E 17, BAUD_M 0)
+ */
+ U0BAUD = 0;
+ U0GCR = (UxGCR_CPOL_NEGATIVE |
+ UxGCR_CPHA_FIRST_EDGE |
+ UxGCR_ORDER_MSB |
+ (17 << UxGCR_BAUD_E_SHIFT));
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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) __critical
+{
+ return ao_tick_count;
+}
+
+static __xdata uint8_t ao_forever;
+
+void
+ao_delay(uint16_t ticks)
+{
+ ao_alarm(ticks);
+ ao_sleep(&ao_forever);
+ ao_clear_alarm();
+}
+
+#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_timer_isr(void) __interrupt 9
+{
+ ++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)
+{
+ /* NOTE: This uses a timer only present on cc1111 architecture. */
+
+ /* disable timer 1 */
+ T1CTL = 0;
+
+ /* set the sample rate */
+ T1CC0H = T1_SAMPLE_TIME >> 8;
+ T1CC0L = (uint8_t) T1_SAMPLE_TIME;
+
+ T1CCTL0 = T1CCTL_MODE_COMPARE;
+ T1CCTL1 = 0;
+ T1CCTL2 = 0;
+
+ /* clear timer value */
+ T1CNTL = 0;
+
+ /* enable overflow interrupt */
+ OVFIM = 1;
+ /* enable timer 1 interrupt */
+ T1IE = 1;
+
+ /* enable timer 1 in module mode, dividing by 8 */
+ T1CTL = T1CTL_MODE_MODULO | T1CTL_DIV_8;
+}
+
+/*
+ * AltOS always cranks the clock to the max frequency
+ */
+void
+ao_clock_init(void)
+{
+ /* Switch system clock to crystal oscilator */
+ CLKCON = (CLKCON & ~CLKCON_OSC_MASK) | (CLKCON_OSC_XTAL);
+
+ while (!(SLEEP & SLEEP_XOSC_STB))
+ ;
+
+ /* Crank up the timer tick and system clock speed */
+ CLKCON = ((CLKCON & ~(CLKCON_TICKSPD_MASK | CLKCON_CLKSPD_MASK)) |
+ (CLKCON_TICKSPD_1 | CLKCON_CLKSPD_1));
+
+ while ((CLKCON & (CLKCON_TICKSPD_MASK|CLKCON_CLKSPD_MASK)) !=
+ (CLKCON_TICKSPD_1 | CLKCON_CLKSPD_1))
+ ;
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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"
+
+struct ao_task __xdata ao_usb_task;
+
+static __xdata uint16_t ao_usb_in_bytes;
+static __pdata uint16_t ao_usb_in_bytes_last;
+static __xdata uint16_t ao_usb_out_bytes;
+static __pdata uint8_t ao_usb_iif;
+static __pdata uint8_t ao_usb_running;
+
+static void
+ao_usb_set_interrupts(void)
+{
+ /* IN interrupts on the control an IN endpoints */
+ USBIIE = (1 << AO_USB_CONTROL_EP) | (1 << AO_USB_IN_EP);
+
+ /* OUT interrupts on the OUT endpoint */
+ USBOIE = (1 << AO_USB_OUT_EP);
+
+ /* Only care about reset */
+ USBCIE = USBCIE_RSTIE;
+}
+
+/* This interrupt is shared with port 2,
+ * so when we hook that up, fix this
+ */
+void
+ao_usb_isr(void) __interrupt 6
+{
+ USBIF = 0;
+ ao_usb_iif |= USBIIF;
+ if (ao_usb_iif & 1)
+ ao_wakeup(&ao_usb_task);
+ if (ao_usb_iif & (1 << AO_USB_IN_EP))
+ ao_wakeup(&ao_usb_in_bytes);
+
+ if (USBOIF & (1 << AO_USB_OUT_EP))
+ ao_wakeup(&ao_stdin_ready);
+
+ if (USBCIF & USBCIF_RSTIF)
+ ao_usb_set_interrupts();
+#if HAS_BTM
+#if BT_LINK_ON_P2
+ ao_btm_isr();
+#endif
+#endif
+}
+
+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;
+
+__pdata uint8_t ao_usb_ep0_state;
+uint8_t * __pdata ao_usb_ep0_in_data;
+__pdata uint8_t ao_usb_ep0_in_len;
+__pdata uint8_t ao_usb_ep0_in_buf[2];
+__pdata uint8_t ao_usb_ep0_out_len;
+__xdata uint8_t *__pdata ao_usb_ep0_out_data;
+__pdata uint8_t ao_usb_configuration;
+
+/* Send an IN data packet */
+static void
+ao_usb_ep0_flush(void)
+{
+ __pdata uint8_t this_len;
+ __pdata uint8_t cs0;
+
+ /* If the IN packet hasn't been picked up, just return */
+ USBINDEX = 0;
+ cs0 = USBCS0;
+ if (cs0 & USBCS0_INPKT_RDY)
+ return;
+
+ this_len = ao_usb_ep0_in_len;
+ if (this_len > AO_USB_CONTROL_SIZE)
+ this_len = AO_USB_CONTROL_SIZE;
+ cs0 = USBCS0_INPKT_RDY;
+ if (this_len != AO_USB_CONTROL_SIZE) {
+ cs0 = USBCS0_INPKT_RDY | USBCS0_DATA_END;
+ ao_usb_ep0_state = AO_USB_EP0_IDLE;
+ }
+ ao_usb_ep0_in_len -= this_len;
+ while (this_len--)
+ USBFIFO[0] = *ao_usb_ep0_in_data++;
+ USBINDEX = 0;
+ USBCS0 = cs0;
+}
+
+__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)
+{
+ __code uint8_t *__pdata descriptor;
+ __pdata uint8_t type = value >> 8;
+ __pdata 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];
+ }
+}
+
+/* Read data from the ep0 OUT fifo
+ */
+static void
+ao_usb_ep0_fill(void)
+{
+ __pdata uint8_t len;
+
+ USBINDEX = 0;
+ len = USBCNT0;
+ if (len > ao_usb_ep0_out_len)
+ len = ao_usb_ep0_out_len;
+ ao_usb_ep0_out_len -= len;
+ while (len--)
+ *ao_usb_ep0_out_data++ = USBFIFO[0];
+}
+
+void
+ao_usb_ep0_queue_byte(uint8_t a)
+{
+ ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a;
+}
+
+void
+ao_usb_set_address(uint8_t address)
+{
+ ao_usb_running = 1;
+ USBADDR = address | 0x80;
+ while (USBADDR & 0x80)
+ ;
+}
+
+static void
+ao_usb_set_configuration(void)
+{
+ /* Set the IN max packet size, double buffered */
+ USBINDEX = AO_USB_IN_EP;
+ USBMAXI = AO_USB_IN_SIZE >> 3;
+ USBCSIH |= USBCSIH_IN_DBL_BUF;
+
+ /* Set the OUT max packet size, double buffered */
+ USBINDEX = AO_USB_OUT_EP;
+ USBMAXO = AO_USB_OUT_SIZE >> 3;
+ USBCSOH = USBCSOH_OUT_DBL_BUF;
+}
+
+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();
+ if (ao_usb_ep0_out_len != 0)
+ 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;
+ }
+ USBINDEX = 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:
+ switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) {
+ case AO_USB_RECIP_DEVICE:
+ 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_SET_ADDRESS:
+ ao_usb_set_address(ao_usb_setup.value);
+ break;
+ case AO_USB_REQ_GET_DESCRIPTOR:
+ ao_usb_get_descriptor(ao_usb_setup.value);
+ break;
+ case AO_USB_REQ_GET_CONFIGURATION:
+ ao_usb_ep0_queue_byte(ao_usb_configuration);
+ break;
+ case AO_USB_REQ_SET_CONFIGURATION:
+ ao_usb_configuration = ao_usb_setup.value;
+ ao_usb_set_configuration();
+ break;
+ }
+ break;
+ case AO_USB_RECIP_INTERFACE:
+ #pragma disable_warning 110
+ 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:
+ 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:
+ switch (ao_usb_setup.request) {
+ case SET_LINE_CODING:
+ ao_usb_ep0_out_len = 7;
+ ao_usb_ep0_out_data = (__xdata uint8_t *) &ao_usb_line_coding;
+ break;
+ case GET_LINE_CODING:
+ 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;
+ ao_usb_ep0_flush();
+ }
+}
+
+/* End point 0 receives all of the control messages. */
+static void
+ao_usb_ep0(void)
+{
+ __pdata uint8_t cs0;
+
+ ao_usb_ep0_state = AO_USB_EP0_IDLE;
+ for (;;) {
+ __critical for (;;) {
+ if (ao_usb_iif & 1) {
+ ao_usb_iif &= ~1;
+ break;
+ }
+ ao_sleep(&ao_usb_task);
+ }
+ USBINDEX = 0;
+ cs0 = USBCS0;
+ if (cs0 & USBCS0_SETUP_END) {
+ ao_usb_ep0_state = AO_USB_EP0_IDLE;
+ USBCS0 = USBCS0_CLR_SETUP_END;
+ }
+ if (cs0 & USBCS0_SENT_STALL) {
+ ao_usb_ep0_state = AO_USB_EP0_IDLE;
+ USBCS0 &= ~USBCS0_SENT_STALL;
+ }
+ if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN &&
+ (cs0 & USBCS0_INPKT_RDY) == 0)
+ {
+ ao_usb_ep0_flush();
+ }
+ if (cs0 & USBCS0_OUTPKT_RDY) {
+ switch (ao_usb_ep0_state) {
+ case AO_USB_EP0_IDLE:
+ ao_usb_ep0_setup();
+ break;
+ case AO_USB_EP0_DATA_OUT:
+ ao_usb_ep0_fill();
+ if (ao_usb_ep0_out_len == 0)
+ ao_usb_ep0_state = AO_USB_EP0_IDLE;
+ USBINDEX = 0;
+ if (ao_usb_ep0_state == AO_USB_EP0_IDLE)
+ USBCS0 = USBCS0_CLR_OUTPKT_RDY | USBCS0_DATA_END;
+ else
+ USBCS0 = USBCS0_CLR_OUTPKT_RDY;
+ break;
+ }
+ }
+ }
+}
+
+/* Wait for a free IN buffer */
+static void
+ao_usb_in_wait(void)
+{
+ for (;;) {
+ USBINDEX = AO_USB_IN_EP;
+ if ((USBCSIL & USBCSIL_INPKT_RDY) == 0)
+ break;
+ ao_sleep(&ao_usb_in_bytes);
+ }
+}
+
+/* Send the current IN packet */
+static void
+ao_usb_in_send(void)
+{
+ USBINDEX = AO_USB_IN_EP;
+ USBCSIL |= USBCSIL_INPKT_RDY;
+ ao_usb_in_bytes_last = ao_usb_in_bytes;
+ ao_usb_in_bytes = 0;
+}
+
+void
+ao_usb_flush(void) __critical
+{
+ if (!ao_usb_running)
+ return;
+
+ /* If there are pending bytes, or if the last packet was full,
+ * send another IN packet
+ */
+ if (ao_usb_in_bytes || (ao_usb_in_bytes_last == AO_USB_IN_SIZE)) {
+ 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, sending the packet when full */
+ USBFIFO[AO_USB_IN_EP << 1] = c;
+ if (++ao_usb_in_bytes == AO_USB_IN_SIZE)
+ ao_usb_in_send();
+}
+
+char
+ao_usb_pollchar(void) __critical
+{
+ char c;
+ if (ao_usb_out_bytes == 0) {
+ USBINDEX = AO_USB_OUT_EP;
+ if ((USBCSOL & USBCSOL_OUTPKT_RDY) == 0)
+ return AO_READ_AGAIN;
+ ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL;
+ if (ao_usb_out_bytes == 0) {
+ USBINDEX = AO_USB_OUT_EP;
+ USBCSOL &= ~USBCSOL_OUTPKT_RDY;
+ return AO_READ_AGAIN;
+ }
+ }
+ --ao_usb_out_bytes;
+ c = USBFIFO[AO_USB_OUT_EP << 1];
+ if (ao_usb_out_bytes == 0) {
+ USBINDEX = AO_USB_OUT_EP;
+ USBCSOL &= ~USBCSOL_OUTPKT_RDY;
+ }
+ return c;
+}
+
+char
+ao_usb_getchar(void) __critical
+{
+ char c;
+
+ while ((c = ao_usb_pollchar()) == AO_READ_AGAIN)
+ ao_sleep(&ao_stdin_ready);
+ return c;
+}
+
+void
+ao_usb_enable(void)
+{
+ /* Turn on the USB controller */
+ SLEEP |= SLEEP_USB_EN;
+
+ ao_usb_set_configuration();
+
+ ao_usb_set_interrupts();
+
+ /* enable USB interrupts */
+ IEN2 |= IEN2_USBIE;
+
+ /* Clear any pending interrupts */
+ USBCIF = 0;
+ USBOIF = 0;
+ USBIIF = 0;
+}
+
+void
+ao_usb_disable(void)
+{
+ /* Disable USB interrupts */
+ USBIIE = 0;
+ USBOIE = 0;
+ USBCIE = 0;
+ IEN2 &= ~IEN2_USBIE;
+
+ /* Clear any pending interrupts */
+ USBCIF = 0;
+ USBOIF = 0;
+ USBIIF = 0;
+
+ /* Turn off the USB controller */
+ SLEEP &= ~SLEEP_USB_EN;
+}
+
+void
+ao_usb_init(void)
+{
+ ao_usb_enable();
+
+ ao_add_task(&ao_usb_task, ao_usb_ep0, "usb");
+ ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush);
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_ */
--- /dev/null
+/*-------------------------------------------------------------------------
+ Register Declarations for the ChipCon CC1111 Processor Range
+
+ Copyright © 2008 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.
+
+ Adapted from the Cygnal C8051F12x config file which is:
+
+ Copyright (C) 2003 - Maarten Brock, sourceforge.brock@dse.nl
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-------------------------------------------------------------------------*/
+
+#ifndef _CC1111_H_
+#define _CC1111_H_
+#include <cc1110.h>
+#include <stdint.h>
+
+__sfr __at 0xA8 IEN0; /* Interrupt Enable 0 Register */
+
+sbit __at 0xA8 RFTXRXIE; /* RF TX/RX done interrupt enable */
+sbit __at 0xA9 ADCIE; /* ADC interrupt enable */
+sbit __at 0xAA URX0IE; /* USART0 RX interrupt enable */
+sbit __at 0xAB URX1IE; /* USART1 RX interrupt enable (shared with I2S RX) */
+sbit __at 0xAB I2SRXIE; /* I2S RX interrupt enable (shared with USART1 RX) */
+sbit __at 0xAC ENCIE; /* AES encryption/decryption interrupt enable */
+sbit __at 0xAD STIE; /* Sleep Timer interrupt enable */
+sbit __at 0xAF EA; /* Enable All */
+
+#define IEN0_EA (1 << 7)
+#define IEN0_STIE (1 << 5)
+#define IEN0_ENCIE (1 << 4)
+#define IEN0_URX1IE (1 << 3)
+#define IEN0_I2SRXIE (1 << 3)
+#define IEN0_URX0IE (1 << 2)
+#define IEN0_ADCIE (1 << 1)
+#define IEN0_RFTXRXIE (1 << 0)
+
+__sfr __at 0xB8 IEN1; /* Interrupt Enable 1 Register */
+
+#define IEN1_P0IE (1 << 5) /* Port 0 interrupt enable */
+#define IEN1_T4IE (1 << 4) /* Timer 4 interrupt enable */
+#define IEN1_T3IE (1 << 3) /* Timer 3 interrupt enable */
+#define IEN1_T2IE (1 << 2) /* Timer 2 interrupt enable */
+#define IEN1_T1IE (1 << 1) /* Timer 1 interrupt enable */
+#define IEN1_DMAIE (1 << 0) /* DMA transfer interrupt enable */
+
+/* IEN2 */
+__sfr __at 0x9A IEN2; /* Interrupt Enable 2 Register */
+
+#define IEN2_WDTIE (1 << 5) /* Watchdog timer interrupt enable */
+#define IEN2_P1IE (1 << 4) /* Port 1 interrupt enable */
+#define IEN2_UTX1IE (1 << 3) /* USART1 TX interrupt enable */
+#define IEN2_I2STXIE (1 << 3) /* I2S TX interrupt enable */
+#define IEN2_UTX0IE (1 << 2) /* USART0 TX interrupt enable */
+#define IEN2_P2IE (1 << 1) /* Port 2 interrupt enable */
+#define IEN2_USBIE (1 << 1) /* USB interrupt enable */
+#define IEN2_RFIE (1 << 0) /* RF general interrupt enable */
+
+/* CLKCON 0xC6 */
+__sfr __at 0xC6 CLKCON; /* Clock Control */
+
+#define CLKCON_OSC32K_RC (1 << 7)
+#define CLKCON_OSC32K_XTAL (0 << 7)
+#define CLKCON_OSC32K_MASK (1 << 7)
+#define CLKCON_OSC_RC (1 << 6)
+#define CLKCON_OSC_XTAL (0 << 6)
+#define CLKCON_OSC_MASK (1 << 6)
+#define CLKCON_TICKSPD_MASK (7 << 3)
+# define CLKCON_TICKSPD_1 (0 << 3)
+# define CLKCON_TICKSPD_1_2 (1 << 3)
+# define CLKCON_TICKSPD_1_4 (2 << 3)
+# define CLKCON_TICKSPD_1_8 (3 << 3)
+# define CLKCON_TICKSPD_1_16 (4 << 3)
+# define CLKCON_TICKSPD_1_32 (5 << 3)
+# define CLKCON_TICKSPD_1_64 (6 << 3)
+# define CLKCON_TICKSPD_1_128 (7 << 3)
+
+#define CLKCON_CLKSPD_MASK (7 << 0)
+# define CLKCON_CLKSPD_1 (0 << 0)
+# define CLKCON_CLKSPD_1_2 (1 << 0)
+# define CLKCON_CLKSPD_1_4 (2 << 0)
+# define CLKCON_CLKSPD_1_8 (3 << 0)
+# define CLKCON_CLKSPD_1_16 (4 << 0)
+# define CLKCON_CLKSPD_1_32 (5 << 0)
+# define CLKCON_CLKSPD_1_64 (6 << 0)
+# define CLKCON_CLKSPD_1_128 (7 << 0)
+
+/* SLEEP 0xBE */
+#define SLEEP_USB_EN (1 << 7)
+#define SLEEP_XOSC_STB (1 << 6)
+#define SLEEP_HFRC_STB (1 << 5)
+#define SLEEP_RST_POWER (0 << 3)
+#define SLEEP_RST_EXTERNAL (1 << 3)
+#define SLEEP_RST_WATCHDOG (2 << 3)
+#define SLEEP_RST_MASK (3 << 3)
+#define SLEEP_OSC_PD (1 << 2)
+#define SLEEP_MODE_PM0 (0 << 0)
+#define SLEEP_MODE_PM1 (1 << 0)
+#define SLEEP_MODE_PM2 (2 << 0)
+#define SLEEP_MODE_PM3 (3 << 0)
+#define SLEEP_MODE_MASK (3 << 0)
+
+/* PCON 0x87 */
+__sfr __at 0x87 PCON; /* Power Mode Control Register */
+
+#define PCON_IDLE (1 << 0)
+
+/*
+ * TCON
+ */
+__sfr __at 0x88 TCON; /* CPU Interrupt Flag 1 */
+
+sbit __at 0x8F URX1IF; /* USART1 RX interrupt flag. Automatically cleared */
+sbit __at 0x8F I2SRXIF; /* I2S RX interrupt flag. Automatically cleared */
+sbit __at 0x8D ADCIF; /* ADC interrupt flag. Automatically cleared */
+sbit __at 0x8B URX0IF; /* USART0 RX interrupt flag. Automatically cleared */
+sbit __at 0x89 RFTXRXIF; /* RF TX/RX complete interrupt flag. Automatically cleared */
+
+#define TCON_URX1IF (1 << 7)
+#define TCON_I2SRXIF (1 << 7)
+#define TCON_ADCIF (1 << 5)
+#define TCON_URX0IF (1 << 3)
+#define TCON_RFTXRXIF (1 << 1)
+
+/*
+ * S0CON
+ */
+__sfr __at 0x98 S0CON; /* CPU Interrupt Flag 2 */
+
+sbit __at 0x98 ENCIF_0; /* AES interrupt 0. */
+sbit __at 0x99 ENCIF_1; /* AES interrupt 1. */
+
+#define S0CON_ENCIF_1 (1 << 1)
+#define S0CON_ENCIF_0 (1 << 0)
+
+/*
+ * S1CON
+ */
+__sfr __at 0x9B S1CON; /* CPU Interrupt Flag 3 */
+
+#define S1CON_RFIF_1 (1 << 1)
+#define S1CON_RFIF_0 (1 << 0)
+
+/*
+ * IRCON
+ */
+__sfr __at 0xC0 IRCON; /* CPU Interrupt Flag 4 */
+
+sbit __at 0xC0 DMAIF; /* DMA complete interrupt flag */
+sbit __at 0xC1 T1IF; /* Timer 1 interrupt flag. Automatically cleared */
+sbit __at 0xC2 T2IF; /* Timer 2 interrupt flag. Automatically cleared */
+sbit __at 0xC3 T3IF; /* Timer 3 interrupt flag. Automatically cleared */
+sbit __at 0xC4 T4IF; /* Timer 4 interrupt flag. Automatically cleared */
+sbit __at 0xC5 P0IF; /* Port0 interrupt flag */
+sbit __at 0xC7 STIF; /* Sleep Timer interrupt flag */
+
+#define IRCON_DMAIF (1 << 0) /* DMA complete interrupt flag */
+#define IRCON_T1IF (1 << 1) /* Timer 1 interrupt flag. Automatically cleared */
+#define IRCON_T2IF (1 << 2) /* Timer 2 interrupt flag. Automatically cleared */
+#define IRCON_T3IF (1 << 3) /* Timer 3 interrupt flag. Automatically cleared */
+#define IRCON_T4IF (1 << 4) /* Timer 4 interrupt flag. Automatically cleared */
+#define IRCON_P0IF (1 << 5) /* Port0 interrupt flag */
+#define IRCON_STIF (1 << 7) /* Sleep Timer interrupt flag */
+
+/*
+ * IRCON2
+ */
+__sfr __at 0xE8 IRCON2; /* CPU Interrupt Flag 5 */
+
+sbit __at 0xE8 USBIF; /* USB interrupt flag (shared with Port2) */
+sbit __at 0xE8 P2IF; /* Port2 interrupt flag (shared with USB) */
+sbit __at 0xE9 UTX0IF; /* USART0 TX interrupt flag */
+sbit __at 0xEA UTX1IF; /* USART1 TX interrupt flag (shared with I2S TX) */
+sbit __at 0xEA I2STXIF; /* I2S TX interrupt flag (shared with USART1 TX) */
+sbit __at 0xEB P1IF; /* Port1 interrupt flag */
+sbit __at 0xEC WDTIF; /* Watchdog timer interrupt flag */
+
+#define IRCON2_USBIF (1 << 0) /* USB interrupt flag (shared with Port2) */
+#define IRCON2_P2IF (1 << 0) /* Port2 interrupt flag (shared with USB) */
+#define IRCON2_UTX0IF (1 << 1) /* USART0 TX interrupt flag */
+#define IRCON2_UTX1IF (1 << 2) /* USART1 TX interrupt flag (shared with I2S TX) */
+#define IRCON2_I2STXIF (1 << 2) /* I2S TX interrupt flag (shared with USART1 TX) */
+#define IRCON2_P1IF (1 << 3) /* Port1 interrupt flag */
+#define IRCON2_WDTIF (1 << 4) /* Watchdog timer interrupt flag */
+
+/*
+ * IP1 - Interrupt Priority 1
+ */
+
+/*
+ * Interrupt priority groups:
+ *
+ * IPG0 RFTXRX RF DMA
+ * IPG1 ADC T1 P2INT/USB
+ * IPG2 URX0 T2 UTX0
+ * IPG3 URX1/I2SRX T3 UTX1 / I2STX
+ * IPG4 ENC T4 P1INT
+ * IPG5 ST P0INT WDT
+ *
+ * Priority = (IP1 << 1) | IP0. Higher priority interrupts served first
+ */
+
+__sfr __at 0xB9 IP1; /* Interrupt Priority 1 */
+__sfr __at 0xA9 IP0; /* Interrupt Priority 0 */
+
+#define IP1_IPG5 (1 << 5)
+#define IP1_IPG4 (1 << 4)
+#define IP1_IPG3 (1 << 3)
+#define IP1_IPG2 (1 << 2)
+#define IP1_IPG1 (1 << 1)
+#define IP1_IPG0 (1 << 0)
+
+#define IP0_IPG5 (1 << 5)
+#define IP0_IPG4 (1 << 4)
+#define IP0_IPG3 (1 << 3)
+#define IP0_IPG2 (1 << 2)
+#define IP0_IPG1 (1 << 1)
+#define IP0_IPG0 (1 << 0)
+
+/*
+ * Timer 1
+ */
+#define T1CTL_MODE_SUSPENDED (0 << 0)
+#define T1CTL_MODE_FREE (1 << 0)
+#define T1CTL_MODE_MODULO (2 << 0)
+#define T1CTL_MODE_UP_DOWN (3 << 0)
+#define T1CTL_MODE_MASK (3 << 0)
+#define T1CTL_DIV_1 (0 << 2)
+#define T1CTL_DIV_8 (1 << 2)
+#define T1CTL_DIV_32 (2 << 2)
+#define T1CTL_DIV_128 (3 << 2)
+#define T1CTL_DIV_MASK (3 << 2)
+#define T1CTL_OVFIF (1 << 4)
+#define T1CTL_CH0IF (1 << 5)
+#define T1CTL_CH1IF (1 << 6)
+#define T1CTL_CH2IF (1 << 7)
+
+#define T1CCTL_NO_CAPTURE (0 << 0)
+#define T1CCTL_CAPTURE_RISING (1 << 0)
+#define T1CCTL_CAPTURE_FALLING (2 << 0)
+#define T1CCTL_CAPTURE_BOTH (3 << 0)
+#define T1CCTL_CAPTURE_MASK (3 << 0)
+
+#define T1CCTL_MODE_CAPTURE (0 << 2)
+#define T1CCTL_MODE_COMPARE (1 << 2)
+
+#define T1CTL_CMP_SET (0 << 3)
+#define T1CTL_CMP_CLEAR (1 << 3)
+#define T1CTL_CMP_TOGGLE (2 << 3)
+#define T1CTL_CMP_SET_CLEAR (3 << 3)
+#define T1CTL_CMP_CLEAR_SET (4 << 3)
+
+#define T1CTL_IM_DISABLED (0 << 6)
+#define T1CTL_IM_ENABLED (1 << 6)
+
+#define T1CTL_CPSEL_NORMAL (0 << 7)
+#define T1CTL_CPSEL_RF (1 << 7)
+
+/*
+ * Timer 3 and Timer 4
+ */
+
+/* Timer count */
+__sfr __at 0xCA T3CNT;
+__sfr __at 0xEA T4CNT;
+
+/* Timer control */
+
+__sfr __at 0xCB T3CTL;
+__sfr __at 0xEB T4CTL;
+
+#define TxCTL_DIV_1 (0 << 5)
+#define TxCTL_DIV_2 (1 << 5)
+#define TxCTL_DIV_4 (2 << 5)
+#define TxCTL_DIV_8 (3 << 5)
+#define TxCTL_DIV_16 (4 << 5)
+#define TxCTL_DIV_32 (5 << 5)
+#define TxCTL_DIV_64 (6 << 5)
+#define TxCTL_DIV_128 (7 << 5)
+#define TxCTL_START (1 << 4)
+#define TxCTL_OVFIM (1 << 3)
+#define TxCTL_CLR (1 << 2)
+#define TxCTL_MODE_FREE (0 << 0)
+#define TxCTL_MODE_DOWN (1 << 0)
+#define TxCTL_MODE_MODULO (2 << 0)
+#define TxCTL_MODE_UP_DOWN (3 << 0)
+
+/* Timer 4 channel 0 compare control */
+
+__sfr __at 0xCC T3CCTL0;
+__sfr __at 0xCE T3CCTL1;
+__sfr __at 0xEC T4CCTL0;
+__sfr __at 0xEE T4CCTL1;
+
+#define TxCCTLy_IM (1 << 6)
+#define TxCCTLy_CMP_SET (0 << 3)
+#define TxCCTLy_CMP_CLEAR (1 << 3)
+#define TxCCTLy_CMP_TOGGLE (2 << 3)
+#define TxCCTLy_CMP_SET_UP_CLEAR_DOWN (3 << 3)
+#define TxCCTLy_CMP_CLEAR_UP_SET_DOWN (4 << 3)
+#define TxCCTLy_CMP_SET_CLEAR_FF (5 << 3)
+#define TxCCTLy_CMP_CLEAR_SET_00 (6 << 3)
+#define TxCCTLy_CMP_MODE_ENABLE (1 << 2)
+
+/* Timer compare value */
+__sfr __at 0xCD T3CC0;
+__sfr __at 0xCF T3CC1;
+__sfr __at 0xED T4CC0;
+__sfr __at 0xEF T4CC1;
+
+/*
+ * Peripheral control
+ */
+
+__sfr __at 0xf1 PERCFG;
+#define PERCFG_T1CFG_ALT_1 (0 << 6)
+#define PERCFG_T1CFG_ALT_2 (1 << 6)
+#define PERCFG_T1CFG_ALT_MASK (1 << 6)
+
+#define PERCFG_T3CFG_ALT_1 (0 << 5)
+#define PERCFG_T3CFG_ALT_2 (1 << 5)
+#define PERCFG_T3CFG_ALT_MASK (1 << 5)
+
+#define PERCFG_T4CFG_ALT_1 (0 << 4)
+#define PERCFG_T4CFG_ALT_2 (1 << 4)
+#define PERCFG_T4CFG_ALT_MASK (1 << 4)
+
+#define PERCFG_U1CFG_ALT_1 (0 << 1)
+#define PERCFG_U1CFG_ALT_2 (1 << 1)
+#define PERCFG_U1CFG_ALT_MASK (1 << 1)
+
+#define PERCFG_U0CFG_ALT_1 (0 << 0)
+#define PERCFG_U0CFG_ALT_2 (1 << 0)
+#define PERCFG_U0CFG_ALT_MASK (1 << 0)
+
+/* directly addressed USB registers */
+__xdata __at (0xde00) volatile uint8_t USBADDR;
+__xdata __at (0xde01) volatile uint8_t USBPOW;
+__xdata __at (0xde02) volatile uint8_t USBIIF;
+
+__xdata __at (0xde04) volatile uint8_t USBOIF;
+
+__xdata __at (0xde06) volatile uint8_t USBCIF;
+
+# define USBCIF_SOFIF (1 << 3)
+# define USBCIF_RSTIF (1 << 2)
+# define USBCIF_RESUMEIF (1 << 1)
+# define USBCIF_SUSPENDIF (1 << 0)
+
+__xdata __at (0xde07) volatile uint8_t USBIIE;
+
+__xdata __at (0xde09) volatile uint8_t USBOIE;
+
+__xdata __at (0xde0b) volatile uint8_t USBCIE;
+
+# define USBCIE_SOFIE (1 << 3)
+# define USBCIE_RSTIE (1 << 2)
+# define USBCIE_RESUMEIE (1 << 1)
+# define USBCIE_SUSPENDIE (1 << 0)
+
+__xdata __at (0xde0c) volatile uint8_t USBFRML;
+__xdata __at (0xde0d) volatile uint8_t USBFRMH;
+__xdata __at (0xde0e) volatile uint8_t USBINDEX;
+
+/* indexed USB registers, must set USBINDEX to 0-5 */
+__xdata __at (0xde10) volatile uint8_t USBMAXI;
+__xdata __at (0xde11) volatile uint8_t USBCS0;
+
+# define USBCS0_CLR_SETUP_END (1 << 7)
+# define USBCS0_CLR_OUTPKT_RDY (1 << 6)
+# define USBCS0_SEND_STALL (1 << 5)
+# define USBCS0_SETUP_END (1 << 4)
+# define USBCS0_DATA_END (1 << 3)
+# define USBCS0_SENT_STALL (1 << 2)
+# define USBCS0_INPKT_RDY (1 << 1)
+# define USBCS0_OUTPKT_RDY (1 << 0)
+
+__xdata __at (0xde11) volatile uint8_t USBCSIL;
+
+# define USBCSIL_CLR_DATA_TOG (1 << 6)
+# define USBCSIL_SENT_STALL (1 << 5)
+# define USBCSIL_SEND_STALL (1 << 4)
+# define USBCSIL_FLUSH_PACKET (1 << 3)
+# define USBCSIL_UNDERRUN (1 << 2)
+# define USBCSIL_PKT_PRESENT (1 << 1)
+# define USBCSIL_INPKT_RDY (1 << 0)
+
+__xdata __at (0xde12) volatile uint8_t USBCSIH;
+
+# define USBCSIH_AUTOSET (1 << 7)
+# define USBCSIH_ISO (1 << 6)
+# define USBCSIH_FORCE_DATA_TOG (1 << 3)
+# define USBCSIH_IN_DBL_BUF (1 << 0)
+
+__xdata __at (0xde13) volatile uint8_t USBMAXO;
+__xdata __at (0xde14) volatile uint8_t USBCSOL;
+
+# define USBCSOL_CLR_DATA_TOG (1 << 7)
+# define USBCSOL_SENT_STALL (1 << 6)
+# define USBCSOL_SEND_STALL (1 << 5)
+# define USBCSOL_FLUSH_PACKET (1 << 4)
+# define USBCSOL_DATA_ERROR (1 << 3)
+# define USBCSOL_OVERRUN (1 << 2)
+# define USBCSOL_FIFO_FULL (1 << 1)
+# define USBCSOL_OUTPKT_RDY (1 << 0)
+
+__xdata __at (0xde15) volatile uint8_t USBCSOH;
+
+# define USBCSOH_AUTOCLEAR (1 << 7)
+# define USBCSOH_ISO (1 << 6)
+# define USBCSOH_OUT_DBL_BUF (1 << 0)
+
+__xdata __at (0xde16) volatile uint8_t USBCNT0;
+__xdata __at (0xde16) volatile uint8_t USBCNTL;
+__xdata __at (0xde17) volatile uint8_t USBCNTH;
+
+__xdata __at (0xde20) volatile uint8_t USBFIFO[12];
+
+/* ADC Data register, low and high */
+__sfr at 0xBA ADCL;
+__sfr at 0xBB ADCH;
+__xdata __at (0xDFBA) volatile uint16_t ADCXDATA;
+
+/* ADC Control Register 1 */
+__sfr at 0xB4 ADCCON1;
+
+# define ADCCON1_EOC (1 << 7) /* conversion complete */
+# define ADCCON1_ST (1 << 6) /* start conversion */
+
+# define ADCCON1_STSEL_MASK (3 << 4) /* start select */
+# define ADCCON1_STSEL_EXTERNAL (0 << 4) /* P2_0 pin triggers */
+# define ADCCON1_STSEL_FULLSPEED (1 << 4) /* full speed, no waiting */
+# define ADCCON1_STSEL_TIMER1 (2 << 4) /* timer 1 channel 0 */
+# define ADCCON1_STSEL_START (3 << 4) /* set start bit */
+
+# define ADCCON1_RCTRL_MASK (3 << 2) /* random number control */
+# define ADCCON1_RCTRL_COMPLETE (0 << 2) /* operation completed */
+# define ADCCON1_RCTRL_CLOCK_LFSR (1 << 2) /* Clock the LFSR once */
+
+/* ADC Control Register 2 */
+__sfr at 0xB5 ADCCON2;
+
+# define ADCCON2_SREF_MASK (3 << 6) /* reference voltage */
+# define ADCCON2_SREF_1_25V (0 << 6) /* internal 1.25V */
+# define ADCCON2_SREF_EXTERNAL (1 << 6) /* external on AIN7 cc1110 */
+# define ADCCON2_SREF_VDD (2 << 6) /* VDD on the AVDD pin */
+# define ADCCON2_SREF_EXTERNAL_DIFF (3 << 6) /* external on AIN6-7 cc1110 */
+
+# define ADCCON2_SDIV_MASK (3 << 4) /* decimation rate */
+# define ADCCON2_SDIV_64 (0 << 4) /* 7 bits */
+# define ADCCON2_SDIV_128 (1 << 4) /* 9 bits */
+# define ADCCON2_SDIV_256 (2 << 4) /* 10 bits */
+# define ADCCON2_SDIV_512 (3 << 4) /* 12 bits */
+
+# define ADCCON2_SCH_MASK (0xf << 0) /* Sequence channel select */
+# define ADCCON2_SCH_SHIFT 0
+# define ADCCON2_SCH_AIN0 (0 << 0)
+# define ADCCON2_SCH_AIN1 (1 << 0)
+# define ADCCON2_SCH_AIN2 (2 << 0)
+# define ADCCON2_SCH_AIN3 (3 << 0)
+# define ADCCON2_SCH_AIN4 (4 << 0)
+# define ADCCON2_SCH_AIN5 (5 << 0)
+# define ADCCON2_SCH_AIN6 (6 << 0)
+# define ADCCON2_SCH_AIN7 (7 << 0)
+# define ADCCON2_SCH_AIN0_AIN1 (8 << 0)
+# define ADCCON2_SCH_AIN2_AIN3 (9 << 0)
+# define ADCCON2_SCH_AIN4_AIN5 (0xa << 0)
+# define ADCCON2_SCH_AIN6_AIN7 (0xb << 0)
+# define ADCCON2_SCH_GND (0xc << 0)
+# define ADCCON2_SCH_VREF (0xd << 0)
+# define ADCCON2_SCH_TEMP (0xe << 0)
+# define ADCCON2_SCH_VDD_3 (0xf << 0)
+
+
+/* ADC Control Register 3 */
+__sfr at 0xB6 ADCCON3;
+
+# define ADCCON3_EREF_MASK (3 << 6) /* extra conversion reference */
+# define ADCCON3_EREF_1_25 (0 << 6) /* internal 1.25V */
+# define ADCCON3_EREF_EXTERNAL (1 << 6) /* external AIN7 cc1110 */
+# define ADCCON3_EREF_VDD (2 << 6) /* VDD on the AVDD pin */
+# define ADCCON3_EREF_EXTERNAL_DIFF (3 << 6) /* external AIN6-7 cc1110 */
+# define ADCCON3_EDIV_MASK (3 << 4) /* extral decimation */
+# define ADCCON3_EDIV_64 (0 << 4) /* 7 bits */
+# define ADCCON3_EDIV_128 (1 << 4) /* 9 bits */
+# define ADCCON3_EDIV_256 (2 << 4) /* 10 bits */
+# define ADCCON3_EDIV_512 (3 << 4) /* 12 bits */
+# define ADCCON3_ECH_MASK (0xf << 0) /* Sequence channel select */
+# define ADCCON3_ECH_SHIFT 0
+# define ADCCON3_ECH_AIN0 (0 << 0)
+# define ADCCON3_ECH_AIN1 (1 << 0)
+# define ADCCON3_ECH_AIN2 (2 << 0)
+# define ADCCON3_ECH_AIN3 (3 << 0)
+# define ADCCON3_ECH_AIN4 (4 << 0)
+# define ADCCON3_ECH_AIN5 (5 << 0)
+# define ADCCON3_ECH_AIN6 (6 << 0)
+# define ADCCON3_ECH_AIN7 (7 << 0)
+# define ADCCON3_ECH_AIN0_AIN1 (8 << 0)
+# define ADCCON3_ECH_AIN2_AIN3 (9 << 0)
+# define ADCCON3_ECH_AIN4_AIN5 (0xa << 0)
+# define ADCCON3_ECH_AIN6_AIN7 (0xb << 0)
+# define ADCCON3_ECH_GND (0xc << 0)
+# define ADCCON3_ECH_VREF (0xd << 0)
+# define ADCCON3_ECH_TEMP (0xe << 0)
+# define ADCCON3_ECH_VDD_3 (0xf << 0)
+
+/*
+ * ADC configuration register, this selects which
+ * GPIO pins are to be used as ADC inputs
+ */
+__sfr at 0xF2 ADCCFG;
+
+/*
+ * Watchdog timer
+ */
+
+__sfr at 0xc9 WDCTL;
+
+#define WDCTL_CLEAR_FIRST (0xa << 4)
+#define WDCTL_CLEAR_SECOND (0x5 << 4)
+#define WDCTL_EN (1 << 3)
+#define WDCTL_MODE_WATCHDOG (0 << 2)
+#define WDCTL_MODE_TIMER (1 << 2)
+#define WDCTL_MODE_MASK (1 << 2)
+#define WDCTL_INT_32768 (0 << 0)
+#define WDCTL_INT_8192 (1 << 0)
+#define WDCTL_INT_512 (2 << 0)
+#define WDCTL_INT_64 (3 << 0)
+
+/*
+ * Pin selectors, these set which pins are
+ * using their peripheral function
+ */
+__sfr at 0xF3 P0SEL;
+__sfr at 0xF4 P1SEL;
+__sfr at 0xF5 P2SEL;
+
+#define P2SEL_PRI3P1_USART0 (0 << 6)
+#define P2SEL_PRI3P1_USART1 (1 << 6)
+#define P2SEL_PRI3P1_MASK (1 << 6)
+#define P2SEL_PRI2P1_USART1 (0 << 5)
+#define P2SEL_PRI2P1_TIMER3 (1 << 5)
+#define P2SEL_PRI2P1_MASK (1 << 5)
+#define P2SEL_PRI1P1_TIMER1 (0 << 4)
+#define P2SEL_PRI1P1_TIMER4 (1 << 4)
+#define P2SEL_PRI1P1_MASK (1 << 4)
+#define P2SEL_PRI0P1_USART0 (0 << 3)
+#define P2SEL_PRI0P1_TIMER1 (1 << 3)
+#define P2SEL_PRI0P1_MASK (1 << 3)
+#define P2SEL_SELP2_4_GPIO (0 << 2)
+#define P2SEL_SELP2_4_PERIPHERAL (1 << 2)
+#define P2SEL_SELP2_4_MASK (1 << 2)
+#define P2SEL_SELP2_3_GPIO (0 << 1)
+#define P2SEL_SELP2_3_PERIPHERAL (1 << 1)
+#define P2SEL_SELP2_3_MASK (1 << 1)
+#define P2SEL_SELP2_0_GPIO (0 << 0)
+#define P2SEL_SELP2_0_PERIPHERAL (1 << 0)
+#define P2SEL_SELP2_0_MASK (1 << 0)
+
+/*
+ * For pins used as GPIOs, these set which are used as outputs
+ */
+__sfr at 0xFD P0DIR;
+__sfr at 0xFE P1DIR;
+__sfr at 0xFF P2DIR;
+
+#define P2DIR_PRIP0_USART0_USART1 (0 << 6)
+#define P2DIR_PRIP0_USART1_USART0 (1 << 6)
+#define P2DIR_PRIP0_TIMER1_01_USART1 (2 << 6)
+#define P2DIR_PRIP0_TIMER1_2_USART0 (3 << 6)
+#define P2DIR_PRIP0_MASK (3 << 6)
+
+__sfr at 0x8F P0INP;
+
+/* Select between tri-state and pull up/down
+ * for pins P0_0 - P0_7.
+ */
+#define P0INP_MDP0_7_PULL (0 << 7)
+#define P0INP_MDP0_7_TRISTATE (1 << 7)
+#define P0INP_MDP0_6_PULL (0 << 6)
+#define P0INP_MDP0_6_TRISTATE (1 << 6)
+#define P0INP_MDP0_5_PULL (0 << 5)
+#define P0INP_MDP0_5_TRISTATE (1 << 5)
+#define P0INP_MDP0_4_PULL (0 << 4)
+#define P0INP_MDP0_4_TRISTATE (1 << 4)
+#define P0INP_MDP0_3_PULL (0 << 3)
+#define P0INP_MDP0_3_TRISTATE (1 << 3)
+#define P0INP_MDP0_2_PULL (0 << 2)
+#define P0INP_MDP0_2_TRISTATE (1 << 2)
+#define P0INP_MDP0_1_PULL (0 << 1)
+#define P0INP_MDP0_1_TRISTATE (1 << 1)
+#define P0INP_MDP0_0_PULL (0 << 0)
+#define P0INP_MDP0_0_TRISTATE (1 << 0)
+
+__sfr at 0xF6 P1INP;
+
+/* Select between tri-state and pull up/down
+ * for pins P1_2 - P1_7. Pins P1_0 and P1_1 are
+ * always tri-stated
+ */
+#define P1INP_MDP1_7_PULL (0 << 7)
+#define P1INP_MDP1_7_TRISTATE (1 << 7)
+#define P1INP_MDP1_6_PULL (0 << 6)
+#define P1INP_MDP1_6_TRISTATE (1 << 6)
+#define P1INP_MDP1_5_PULL (0 << 5)
+#define P1INP_MDP1_5_TRISTATE (1 << 5)
+#define P1INP_MDP1_4_PULL (0 << 4)
+#define P1INP_MDP1_4_TRISTATE (1 << 4)
+#define P1INP_MDP1_3_PULL (0 << 3)
+#define P1INP_MDP1_3_TRISTATE (1 << 3)
+#define P1INP_MDP1_2_PULL (0 << 2)
+#define P1INP_MDP1_2_TRISTATE (1 << 2)
+
+__sfr at 0xF7 P2INP;
+/* P2INP has three extra bits which are used to choose
+ * between pull-up and pull-down when they are not tri-stated
+ */
+#define P2INP_PDUP2_PULL_UP (0 << 7)
+#define P2INP_PDUP2_PULL_DOWN (1 << 7)
+#define P2INP_PDUP1_PULL_UP (0 << 6)
+#define P2INP_PDUP1_PULL_DOWN (1 << 6)
+#define P2INP_PDUP0_PULL_UP (0 << 5)
+#define P2INP_PDUP0_PULL_DOWN (1 << 5)
+
+/* For the P2 pins, choose between tri-state and pull up/down
+ * mode
+ */
+#define P2INP_MDP2_4_PULL (0 << 4)
+#define P2INP_MDP2_4_TRISTATE (1 << 4)
+#define P2INP_MDP2_3_PULL (0 << 3)
+#define P2INP_MDP2_3_TRISTATE (1 << 3)
+#define P2INP_MDP2_2_PULL (0 << 2)
+#define P2INP_MDP2_2_TRISTATE (1 << 2)
+#define P2INP_MDP2_1_PULL (0 << 1)
+#define P2INP_MDP2_1_TRISTATE (1 << 1)
+#define P2INP_MDP2_0_PULL (0 << 0)
+#define P2INP_MDP2_0_TRISTATE (1 << 0)
+
+/* GPIO interrupt status flags */
+__sfr at 0x89 P0IFG;
+__sfr at 0x8A P1IFG;
+__sfr at 0x8B P2IFG;
+
+#define P0IFG_USB_RESUME (1 << 7)
+
+__sfr at 0x8C PICTL;
+#define PICTL_P2IEN (1 << 5)
+#define PICTL_P0IENH (1 << 4)
+#define PICTL_P0IENL (1 << 3)
+#define PICTL_P2ICON (1 << 2)
+#define PICTL_P1ICON (1 << 1)
+#define PICTL_P0ICON (1 << 0)
+
+/* GPIO pins */
+__sfr at 0x80 P0;
+
+sbit at 0x80 P0_0;
+sbit at 0x81 P0_1;
+sbit at 0x82 P0_2;
+sbit at 0x83 P0_3;
+sbit at 0x84 P0_4;
+sbit at 0x85 P0_5;
+sbit at 0x86 P0_6;
+sbit at 0x87 P0_7;
+
+__sfr at 0x90 P1;
+
+sbit at 0x90 P1_0;
+sbit at 0x91 P1_1;
+sbit at 0x92 P1_2;
+sbit at 0x93 P1_3;
+sbit at 0x94 P1_4;
+sbit at 0x95 P1_5;
+sbit at 0x96 P1_6;
+sbit at 0x97 P1_7;
+
+__sfr at 0xa0 P2;
+
+sbit at 0xa0 P2_0;
+sbit at 0xa1 P2_1;
+sbit at 0xa2 P2_2;
+sbit at 0xa3 P2_3;
+sbit at 0xa4 P2_4;
+
+/* DMA controller */
+struct cc_dma_channel {
+ uint8_t src_high;
+ uint8_t src_low;
+ uint8_t dst_high;
+ uint8_t dst_low;
+ uint8_t len_high;
+ uint8_t len_low;
+ uint8_t cfg0;
+ uint8_t cfg1;
+};
+
+# define DMA_LEN_HIGH_VLEN_MASK (7 << 5)
+# define DMA_LEN_HIGH_VLEN_LEN (0 << 5)
+# define DMA_LEN_HIGH_VLEN_PLUS_1 (1 << 5)
+# define DMA_LEN_HIGH_VLEN (2 << 5)
+# define DMA_LEN_HIGH_VLEN_PLUS_2 (3 << 5)
+# define DMA_LEN_HIGH_VLEN_PLUS_3 (4 << 5)
+# define DMA_LEN_HIGH_MASK (0x1f)
+
+# define DMA_CFG0_WORDSIZE_8 (0 << 7)
+# define DMA_CFG0_WORDSIZE_16 (1 << 7)
+# define DMA_CFG0_TMODE_MASK (3 << 5)
+# define DMA_CFG0_TMODE_SINGLE (0 << 5)
+# define DMA_CFG0_TMODE_BLOCK (1 << 5)
+# define DMA_CFG0_TMODE_REPEATED_SINGLE (2 << 5)
+# define DMA_CFG0_TMODE_REPEATED_BLOCK (3 << 5)
+
+/*
+ * DMA triggers
+ */
+# define DMA_CFG0_TRIGGER_NONE 0
+# define DMA_CFG0_TRIGGER_PREV 1
+# define DMA_CFG0_TRIGGER_T1_CH0 2
+# define DMA_CFG0_TRIGGER_T1_CH1 3
+# define DMA_CFG0_TRIGGER_T1_CH2 4
+# define DMA_CFG0_TRIGGER_T2_OVFL 6
+# define DMA_CFG0_TRIGGER_T3_CH0 7
+# define DMA_CFG0_TRIGGER_T3_CH1 8
+# define DMA_CFG0_TRIGGER_T4_CH0 9
+# define DMA_CFG0_TRIGGER_T4_CH1 10
+# define DMA_CFG0_TRIGGER_IOC_0 12
+# define DMA_CFG0_TRIGGER_IOC_1 13
+# define DMA_CFG0_TRIGGER_URX0 14
+# define DMA_CFG0_TRIGGER_UTX0 15
+# define DMA_CFG0_TRIGGER_URX1 16
+# define DMA_CFG0_TRIGGER_UTX1 17
+# define DMA_CFG0_TRIGGER_FLASH 18
+# define DMA_CFG0_TRIGGER_RADIO 19
+# define DMA_CFG0_TRIGGER_ADC_CHALL 20
+# define DMA_CFG0_TRIGGER_ADC_CH0 21
+# define DMA_CFG0_TRIGGER_ADC_CH1 22
+# define DMA_CFG0_TRIGGER_ADC_CH2 23
+# define DMA_CFG0_TRIGGER_ADC_CH3 24
+# define DMA_CFG0_TRIGGER_ADC_CH4 25
+# define DMA_CFG0_TRIGGER_ADC_CH5 26
+# define DMA_CFG0_TRIGGER_ADC_CH6 27
+# define DMA_CFG0_TRIGGER_I2SRX 27
+# define DMA_CFG0_TRIGGER_ADC_CH7 28
+# define DMA_CFG0_TRIGGER_I2STX 28
+# define DMA_CFG0_TRIGGER_ENC_DW 29
+# define DMA_CFG0_TRIGGER_ENC_UP 30
+
+# define DMA_CFG1_SRCINC_MASK (3 << 6)
+# define DMA_CFG1_SRCINC_0 (0 << 6)
+# define DMA_CFG1_SRCINC_1 (1 << 6)
+# define DMA_CFG1_SRCINC_2 (2 << 6)
+# define DMA_CFG1_SRCINC_MINUS_1 (3 << 6)
+
+# define DMA_CFG1_DESTINC_MASK (3 << 4)
+# define DMA_CFG1_DESTINC_0 (0 << 4)
+# define DMA_CFG1_DESTINC_1 (1 << 4)
+# define DMA_CFG1_DESTINC_2 (2 << 4)
+# define DMA_CFG1_DESTINC_MINUS_1 (3 << 4)
+
+# define DMA_CFG1_IRQMASK (1 << 3)
+# define DMA_CFG1_M8 (1 << 2)
+
+# define DMA_CFG1_PRIORITY_MASK (3 << 0)
+# define DMA_CFG1_PRIORITY_LOW (0 << 0)
+# define DMA_CFG1_PRIORITY_NORMAL (1 << 0)
+# define DMA_CFG1_PRIORITY_HIGH (2 << 0)
+
+/*
+ * DMAARM - DMA Channel Arm
+ */
+
+__sfr at 0xD6 DMAARM;
+
+# define DMAARM_ABORT (1 << 7)
+# define DMAARM_DMAARM4 (1 << 4)
+# define DMAARM_DMAARM3 (1 << 3)
+# define DMAARM_DMAARM2 (1 << 2)
+# define DMAARM_DMAARM1 (1 << 1)
+# define DMAARM_DMAARM0 (1 << 0)
+
+/*
+ * DMAREQ - DMA Channel Start Request and Status
+ */
+
+__sfr at 0xD7 DMAREQ;
+
+# define DMAREQ_DMAREQ4 (1 << 4)
+# define DMAREQ_DMAREQ3 (1 << 3)
+# define DMAREQ_DMAREQ2 (1 << 2)
+# define DMAREQ_DMAREQ1 (1 << 1)
+# define DMAREQ_DMAREQ0 (1 << 0)
+
+/*
+ * DMA configuration 0 address
+ */
+
+__sfr at 0xD5 DMA0CFGH;
+__sfr at 0xD4 DMA0CFGL;
+
+/*
+ * DMA configuration 1-4 address
+ */
+
+__sfr at 0xD3 DMA1CFGH;
+__sfr at 0xD2 DMA1CFGL;
+
+/*
+ * DMAIRQ - DMA Interrupt Flag
+ */
+
+__sfr at 0xD1 DMAIRQ;
+
+# define DMAIRQ_DMAIF4 (1 << 4)
+# define DMAIRQ_DMAIF3 (1 << 3)
+# define DMAIRQ_DMAIF2 (1 << 2)
+# define DMAIRQ_DMAIF1 (1 << 1)
+# define DMAIRQ_DMAIF0 (1 << 0)
+
+/*
+ * UART registers
+ */
+
+/* USART config/status registers */
+__sfr at 0x86 U0CSR;
+__sfr at 0xF8 U1CSR;
+
+# define UxCSR_MODE_UART (1 << 7)
+# define UxCSR_MODE_SPI (0 << 7)
+# define UxCSR_RE (1 << 6)
+# define UxCSR_SLAVE (1 << 5)
+# define UxCSR_MASTER (0 << 5)
+# define UxCSR_FE (1 << 4)
+# define UxCSR_ERR (1 << 3)
+# define UxCSR_RX_BYTE (1 << 2)
+# define UxCSR_TX_BYTE (1 << 1)
+# define UxCSR_ACTIVE (1 << 0)
+
+/* UART configuration registers */
+__sfr at 0xc4 U0UCR;
+__sfr at 0xfb U1UCR;
+
+# define UxUCR_FLUSH (1 << 7)
+# define UxUCR_FLOW_DISABLE (0 << 6)
+# define UxUCR_FLOW_ENABLE (1 << 6)
+# define UxUCR_D9_EVEN_PARITY (0 << 5)
+# define UxUCR_D9_ODD_PARITY (1 << 5)
+# define UxUCR_BIT9_8_BITS (0 << 4)
+# define UxUCR_BIT9_9_BITS (1 << 4)
+# define UxUCR_PARITY_DISABLE (0 << 3)
+# define UxUCR_PARITY_ENABLE (1 << 3)
+# define UxUCR_SPB_1_STOP_BIT (0 << 2)
+# define UxUCR_SPB_2_STOP_BITS (1 << 2)
+# define UxUCR_STOP_LOW (0 << 1)
+# define UxUCR_STOP_HIGH (1 << 1)
+# define UxUCR_START_LOW (0 << 0)
+# define UxUCR_START_HIGH (1 << 0)
+
+/* USART General configuration registers (mostly SPI) */
+__sfr at 0xc5 U0GCR;
+__sfr at 0xfc U1GCR;
+
+# define UxGCR_CPOL_NEGATIVE (0 << 7)
+# define UxGCR_CPOL_POSITIVE (1 << 7)
+# define UxGCR_CPHA_FIRST_EDGE (0 << 6)
+# define UxGCR_CPHA_SECOND_EDGE (1 << 6)
+# define UxGCR_ORDER_LSB (0 << 5)
+# define UxGCR_ORDER_MSB (1 << 5)
+# define UxGCR_BAUD_E_MASK (0x1f)
+# define UxGCR_BAUD_E_SHIFT 0
+
+/* USART data registers */
+__sfr at 0xc1 U0DBUF;
+__xdata __at (0xDFC1) volatile uint8_t U0DBUFXADDR;
+__sfr at 0xf9 U1DBUF;
+__xdata __at (0xDFF9) volatile uint8_t U1DBUFXADDR;
+
+/* USART baud rate registers, M value */
+__sfr at 0xc2 U0BAUD;
+__sfr at 0xfa U1BAUD;
+
+/* Flash controller */
+
+__sfr at 0xAE FCTL;
+#define FCTL_BUSY (1 << 7)
+#define FCTL_SWBSY (1 << 6)
+#define FCTL_CONTRD_ENABLE (1 << 4)
+#define FCTL_WRITE (1 << 1)
+#define FCTL_ERASE (1 << 0)
+
+/* Flash write data. Write two bytes here */
+__sfr at 0xAF FWDATA;
+__xdata __at (0xDFAF) volatile uint8_t FWDATAXADDR;
+
+/* Flash write/erase address */
+__sfr at 0xAD FADDRH;
+__sfr at 0xAC FADDRL;
+
+/* Flash timing */
+__sfr at 0xAB FWT;
+
+/* Radio */
+
+__sfr at 0xD9 RFD;
+__xdata at (0xDFD9) volatile uint8_t RFDXADDR;
+
+__sfr at 0xE9 RFIF;
+#define RFIF_IM_TXUNF (1 << 7)
+#define RFIF_IM_RXOVF (1 << 6)
+#define RFIF_IM_TIMEOUT (1 << 5)
+#define RFIF_IM_DONE (1 << 4)
+#define RFIF_IM_CS (1 << 3)
+#define RFIF_IM_PQT (1 << 2)
+#define RFIF_IM_CCA (1 << 1)
+#define RFIF_IM_SFD (1 << 0)
+
+__sfr at 0x91 RFIM;
+#define RFIM_IM_TXUNF (1 << 7)
+#define RFIM_IM_RXOVF (1 << 6)
+#define RFIM_IM_TIMEOUT (1 << 5)
+#define RFIM_IM_DONE (1 << 4)
+#define RFIM_IM_CS (1 << 3)
+#define RFIM_IM_PQT (1 << 2)
+#define RFIM_IM_CCA (1 << 1)
+#define RFIM_IM_SFD (1 << 0)
+
+__sfr at 0xE1 RFST;
+
+#define RFST_SFSTXON 0x00
+#define RFST_SCAL 0x01
+#define RFST_SRX 0x02
+#define RFST_STX 0x03
+#define RFST_SIDLE 0x04
+
+__xdata __at (0xdf00) uint8_t RF[0x3c];
+
+__xdata __at (0xdf2f) uint8_t RF_IOCFG2;
+#define RF_IOCFG2_OFF 0x2f
+
+__xdata __at (0xdf30) uint8_t RF_IOCFG1;
+#define RF_IOCFG1_OFF 0x30
+
+__xdata __at (0xdf31) uint8_t RF_IOCFG0;
+#define RF_IOCFG0_OFF 0x31
+
+__xdata __at (0xdf00) uint8_t RF_SYNC1;
+#define RF_SYNC1_OFF 0x00
+
+__xdata __at (0xdf01) uint8_t RF_SYNC0;
+#define RF_SYNC0_OFF 0x01
+
+__xdata __at (0xdf02) uint8_t RF_PKTLEN;
+#define RF_PKTLEN_OFF 0x02
+
+__xdata __at (0xdf03) uint8_t RF_PKTCTRL1;
+#define RF_PKTCTRL1_OFF 0x03
+#define PKTCTRL1_PQT_MASK (0x7 << 5)
+#define PKTCTRL1_PQT_SHIFT 5
+#define PKTCTRL1_APPEND_STATUS (1 << 2)
+#define PKTCTRL1_ADR_CHK_NONE (0 << 0)
+#define PKTCTRL1_ADR_CHK_NO_BROADCAST (1 << 0)
+#define PKTCTRL1_ADR_CHK_00_BROADCAST (2 << 0)
+#define PKTCTRL1_ADR_CHK_00_FF_BROADCAST (3 << 0)
+
+/* If APPEND_STATUS is used, two bytes will be added to the packet data */
+#define PKT_APPEND_STATUS_0_RSSI_MASK (0xff)
+#define PKT_APPEND_STATUS_0_RSSI_SHIFT 0
+#define PKT_APPEND_STATUS_1_CRC_OK (1 << 7)
+#define PKT_APPEND_STATUS_1_LQI_MASK (0x7f)
+#define PKT_APPEND_STATUS_1_LQI_SHIFT 0
+
+__xdata __at (0xdf04) uint8_t RF_PKTCTRL0;
+#define RF_PKTCTRL0_OFF 0x04
+#define RF_PKTCTRL0_WHITE_DATA (1 << 6)
+#define RF_PKTCTRL0_PKT_FORMAT_NORMAL (0 << 4)
+#define RF_PKTCTRL0_PKT_FORMAT_RANDOM (2 << 4)
+#define RF_PKTCTRL0_CRC_EN (1 << 2)
+#define RF_PKTCTRL0_LENGTH_CONFIG_FIXED (0 << 0)
+#define RF_PKTCTRL0_LENGTH_CONFIG_VARIABLE (1 << 0)
+
+__xdata __at (0xdf05) uint8_t RF_ADDR;
+#define RF_ADDR_OFF 0x05
+
+__xdata __at (0xdf06) uint8_t RF_CHANNR;
+#define RF_CHANNR_OFF 0x06
+
+__xdata __at (0xdf07) uint8_t RF_FSCTRL1;
+#define RF_FSCTRL1_OFF 0x07
+
+#define RF_FSCTRL1_FREQ_IF_SHIFT (0)
+
+__xdata __at (0xdf08) uint8_t RF_FSCTRL0;
+#define RF_FSCTRL0_OFF 0x08
+
+#define RF_FSCTRL0_FREQOFF_SHIFT (0)
+
+__xdata __at (0xdf09) uint8_t RF_FREQ2;
+#define RF_FREQ2_OFF 0x09
+
+__xdata __at (0xdf0a) uint8_t RF_FREQ1;
+#define RF_FREQ1_OFF 0x0a
+
+__xdata __at (0xdf0b) uint8_t RF_FREQ0;
+#define RF_FREQ0_OFF 0x0b
+
+__xdata __at (0xdf0c) uint8_t RF_MDMCFG4;
+#define RF_MDMCFG4_OFF 0x0c
+
+#define RF_MDMCFG4_CHANBW_E_SHIFT 6
+#define RF_MDMCFG4_CHANBW_M_SHIFT 4
+#define RF_MDMCFG4_DRATE_E_SHIFT 0
+
+__xdata __at (0xdf0d) uint8_t RF_MDMCFG3;
+#define RF_MDMCFG3_OFF 0x0d
+
+#define RF_MDMCFG3_DRATE_M_SHIFT 0
+
+__xdata __at (0xdf0e) uint8_t RF_MDMCFG2;
+#define RF_MDMCFG2_OFF 0x0e
+
+#define RF_MDMCFG2_DEM_DCFILT_OFF (1 << 7)
+#define RF_MDMCFG2_DEM_DCFILT_ON (0 << 7)
+
+#define RF_MDMCFG2_MOD_FORMAT_MASK (7 << 4)
+#define RF_MDMCFG2_MOD_FORMAT_2_FSK (0 << 4)
+#define RF_MDMCFG2_MOD_FORMAT_GFSK (1 << 4)
+#define RF_MDMCFG2_MOD_FORMAT_ASK_OOK (3 << 4)
+#define RF_MDMCFG2_MOD_FORMAT_MSK (7 << 4)
+
+#define RF_MDMCFG2_MANCHESTER_EN (1 << 3)
+
+#define RF_MDMCFG2_SYNC_MODE_MASK (0x7 << 0)
+#define RF_MDMCFG2_SYNC_MODE_NONE (0x0 << 0)
+#define RF_MDMCFG2_SYNC_MODE_15_16 (0x1 << 0)
+#define RF_MDMCFG2_SYNC_MODE_16_16 (0x2 << 0)
+#define RF_MDMCFG2_SYNC_MODE_30_32 (0x3 << 0)
+#define RF_MDMCFG2_SYNC_MODE_NONE_THRES (0x4 << 0)
+#define RF_MDMCFG2_SYNC_MODE_15_16_THRES (0x5 << 0)
+#define RF_MDMCFG2_SYNC_MODE_16_16_THRES (0x6 << 0)
+#define RF_MDMCFG2_SYNC_MODE_30_32_THRES (0x7 << 0)
+
+__xdata __at (0xdf0f) uint8_t RF_MDMCFG1;
+#define RF_MDMCFG1_OFF 0x0f
+
+#define RF_MDMCFG1_FEC_EN (1 << 7)
+#define RF_MDMCFG1_FEC_DIS (0 << 7)
+
+#define RF_MDMCFG1_NUM_PREAMBLE_MASK (7 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_2 (0 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_3 (1 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_4 (2 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_6 (3 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_8 (4 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_12 (5 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_16 (6 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_24 (7 << 4)
+
+#define RF_MDMCFG1_CHANSPC_E_MASK (3 << 0)
+#define RF_MDMCFG1_CHANSPC_E_SHIFT (0)
+
+__xdata __at (0xdf10) uint8_t RF_MDMCFG0;
+#define RF_MDMCFG0_OFF 0x10
+
+#define RF_MDMCFG0_CHANSPC_M_SHIFT (0)
+
+__xdata __at (0xdf11) uint8_t RF_DEVIATN;
+#define RF_DEVIATN_OFF 0x11
+
+#define RF_DEVIATN_DEVIATION_E_SHIFT 4
+#define RF_DEVIATN_DEVIATION_M_SHIFT 0
+
+__xdata __at (0xdf12) uint8_t RF_MCSM2;
+#define RF_MCSM2_OFF 0x12
+#define RF_MCSM2_RX_TIME_RSSI (1 << 4)
+#define RF_MCSM2_RX_TIME_QUAL (1 << 3)
+#define RF_MCSM2_RX_TIME_MASK (0x7)
+#define RF_MCSM2_RX_TIME_SHIFT 0
+#define RF_MCSM2_RX_TIME_END_OF_PACKET (7)
+
+__xdata __at (0xdf13) uint8_t RF_MCSM1;
+#define RF_MCSM1_OFF 0x13
+#define RF_MCSM1_CCA_MODE_ALWAYS (0 << 4)
+#define RF_MCSM1_CCA_MODE_RSSI_BELOW (1 << 4)
+#define RF_MCSM1_CCA_MODE_UNLESS_RECEIVING (2 << 4)
+#define RF_MCSM1_CCA_MODE_RSSI_BELOW_UNLESS_RECEIVING (3 << 4)
+#define RF_MCSM1_RXOFF_MODE_IDLE (0 << 2)
+#define RF_MCSM1_RXOFF_MODE_FSTXON (1 << 2)
+#define RF_MCSM1_RXOFF_MODE_TX (2 << 2)
+#define RF_MCSM1_RXOFF_MODE_RX (3 << 2)
+#define RF_MCSM1_TXOFF_MODE_IDLE (0 << 0)
+#define RF_MCSM1_TXOFF_MODE_FSTXON (1 << 0)
+#define RF_MCSM1_TXOFF_MODE_TX (2 << 0)
+#define RF_MCSM1_TXOFF_MODE_RX (3 << 0)
+
+__xdata __at (0xdf14) uint8_t RF_MCSM0;
+#define RF_MCSM0_OFF 0x14
+#define RF_MCSM0_FS_AUTOCAL_NEVER (0 << 4)
+#define RF_MCSM0_FS_AUTOCAL_FROM_IDLE (1 << 4)
+#define RF_MCSM0_FS_AUTOCAL_TO_IDLE (2 << 4)
+#define RF_MCSM0_FS_AUTOCAL_TO_IDLE_EVERY_4 (3 << 4)
+#define RF_MCSM0_MAGIC_3 (1 << 3)
+#define RF_MCSM0_MAGIC_2 (1 << 2)
+#define RF_MCSM0_CLOSE_IN_RX_0DB (0 << 0)
+#define RF_MCSM0_CLOSE_IN_RX_6DB (1 << 0)
+#define RF_MCSM0_CLOSE_IN_RX_12DB (2 << 0)
+#define RF_MCSM0_CLOSE_IN_RX_18DB (3 << 0)
+
+__xdata __at (0xdf15) uint8_t RF_FOCCFG;
+#define RF_FOCCFG_OFF 0x15
+#define RF_FOCCFG_FOC_BS_CS_GATE (1 << 5)
+#define RF_FOCCFG_FOC_PRE_K_1K (0 << 3)
+#define RF_FOCCFG_FOC_PRE_K_2K (1 << 3)
+#define RF_FOCCFG_FOC_PRE_K_3K (2 << 3)
+#define RF_FOCCFG_FOC_PRE_K_4K (3 << 3)
+#define RF_FOCCFG_FOC_POST_K_PRE_K (0 << 2)
+#define RF_FOCCFG_FOC_POST_K_PRE_K_OVER_2 (1 << 2)
+#define RF_FOCCFG_FOC_LIMIT_0 (0 << 0)
+#define RF_FOCCFG_FOC_LIMIT_BW_OVER_8 (1 << 0)
+#define RF_FOCCFG_FOC_LIMIT_BW_OVER_4 (2 << 0)
+#define RF_FOCCFG_FOC_LIMIT_BW_OVER_2 (3 << 0)
+
+__xdata __at (0xdf16) uint8_t RF_BSCFG;
+#define RF_BSCFG_OFF 0x16
+#define RF_BSCFG_BS_PRE_K_1K (0 << 6)
+#define RF_BSCFG_BS_PRE_K_2K (1 << 6)
+#define RF_BSCFG_BS_PRE_K_3K (2 << 6)
+#define RF_BSCFG_BS_PRE_K_4K (3 << 6)
+#define RF_BSCFG_BS_PRE_KP_1KP (0 << 4)
+#define RF_BSCFG_BS_PRE_KP_2KP (1 << 4)
+#define RF_BSCFG_BS_PRE_KP_3KP (2 << 4)
+#define RF_BSCFG_BS_PRE_KP_4KP (3 << 4)
+#define RF_BSCFG_BS_POST_KI_PRE_KI (0 << 3)
+#define RF_BSCFG_BS_POST_KI_PRE_KI_OVER_2 (1 << 3)
+#define RF_BSCFG_BS_POST_KP_PRE_KP (0 << 2)
+#define RF_BSCFG_BS_POST_KP_PRE_KP_OVER_2 (1 << 2)
+#define RF_BSCFG_BS_LIMIT_0 (0 << 0)
+#define RF_BSCFG_BS_LIMIT_3_125 (1 << 0)
+#define RF_BSCFG_BS_LIMIT_6_25 (2 << 0)
+#define RF_BSCFG_BS_LIMIT_12_5 (3 << 0)
+
+__xdata __at (0xdf17) uint8_t RF_AGCCTRL2;
+#define RF_AGCCTRL2_OFF 0x17
+
+__xdata __at (0xdf18) uint8_t RF_AGCCTRL1;
+#define RF_AGCCTRL1_OFF 0x18
+
+__xdata __at (0xdf19) uint8_t RF_AGCCTRL0;
+#define RF_AGCCTRL0_OFF 0x19
+
+__xdata __at (0xdf1a) uint8_t RF_FREND1;
+#define RF_FREND1_OFF 0x1a
+
+#define RF_FREND1_LNA_CURRENT_SHIFT 6
+#define RF_FREND1_LNA2MIX_CURRENT_SHIFT 4
+#define RF_FREND1_LODIV_BUF_CURRENT_RX_SHIFT 2
+#define RF_FREND1_MIX_CURRENT_SHIFT 0
+
+__xdata __at (0xdf1b) uint8_t RF_FREND0;
+#define RF_FREND0_OFF 0x1b
+
+#define RF_FREND0_LODIV_BUF_CURRENT_TX_MASK (0x3 << 4)
+#define RF_FREND0_LODIV_BUF_CURRENT_TX_SHIFT 4
+#define RF_FREND0_PA_POWER_MASK (0x7)
+#define RF_FREND0_PA_POWER_SHIFT 0
+
+__xdata __at (0xdf1c) uint8_t RF_FSCAL3;
+#define RF_FSCAL3_OFF 0x1c
+
+__xdata __at (0xdf1d) uint8_t RF_FSCAL2;
+#define RF_FSCAL2_OFF 0x1d
+
+__xdata __at (0xdf1e) uint8_t RF_FSCAL1;
+#define RF_FSCAL1_OFF 0x1e
+
+__xdata __at (0xdf1f) uint8_t RF_FSCAL0;
+#define RF_FSCAL0_OFF 0x1f
+
+__xdata __at (0xdf23) uint8_t RF_TEST2;
+#define RF_TEST2_OFF 0x23
+
+#define RF_TEST2_NORMAL_MAGIC 0x88
+#define RF_TEST2_RX_LOW_DATA_RATE_MAGIC 0x81
+
+__xdata __at (0xdf24) uint8_t RF_TEST1;
+#define RF_TEST1_OFF 0x24
+
+#define RF_TEST1_TX_MAGIC 0x31
+#define RF_TEST1_RX_LOW_DATA_RATE_MAGIC 0x35
+
+__xdata __at (0xdf25) uint8_t RF_TEST0;
+#define RF_TEST0_OFF 0x25
+
+#define RF_TEST0_7_2_MASK (0xfc)
+#define RF_TEST0_VCO_SEL_CAL_EN (1 << 1)
+#define RF_TEST0_0_MASK (1)
+
+/* These are undocumented, and must be computed
+ * using the provided tool.
+ */
+__xdata __at (0xdf27) uint8_t RF_PA_TABLE7;
+#define RF_PA_TABLE7_OFF 0x27
+
+__xdata __at (0xdf28) uint8_t RF_PA_TABLE6;
+#define RF_PA_TABLE6_OFF 0x28
+
+__xdata __at (0xdf29) uint8_t RF_PA_TABLE5;
+#define RF_PA_TABLE5_OFF 0x29
+
+__xdata __at (0xdf2a) uint8_t RF_PA_TABLE4;
+#define RF_PA_TABLE4_OFF 0x2a
+
+__xdata __at (0xdf2b) uint8_t RF_PA_TABLE3;
+#define RF_PA_TABLE3_OFF 0x2b
+
+__xdata __at (0xdf2c) uint8_t RF_PA_TABLE2;
+#define RF_PA_TABLE2_OFF 0x2c
+
+__xdata __at (0xdf2d) uint8_t RF_PA_TABLE1;
+#define RF_PA_TABLE1_OFF 0x2d
+
+__xdata __at (0xdf2e) uint8_t RF_PA_TABLE0;
+#define RF_PA_TABLE0_OFF 0x2e
+
+__xdata __at (0xdf36) uint8_t RF_PARTNUM;
+#define RF_PARTNUM_OFF 0x36
+
+__xdata __at (0xdf37) uint8_t RF_VERSION;
+#define RF_VERSION_OFF 0x37
+
+__xdata __at (0xdf38) uint8_t RF_FREQEST;
+#define RF_FREQEST_OFF 0x38
+
+__xdata __at (0xdf39) uint8_t RF_LQI;
+#define RF_LQI_OFF 0x39
+
+#define RF_LQI_CRC_OK (1 << 7)
+#define RF_LQI_LQI_EST_MASK (0x7f)
+
+__xdata __at (0xdf3a) uint8_t RF_RSSI;
+#define RF_RSSI_OFF 0x3a
+
+__xdata __at (0xdf3b) uint8_t RF_MARCSTATE;
+#define RF_MARCSTATE_OFF 0x3b
+
+#define RF_MARCSTATE_MASK 0x1f
+#define RF_MARCSTATE_SLEEP 0x00
+#define RF_MARCSTATE_IDLE 0x01
+#define RF_MARCSTATE_VCOON_MC 0x03
+#define RF_MARCSTATE_REGON_MC 0x04
+#define RF_MARCSTATE_MANCAL 0x05
+#define RF_MARCSTATE_VCOON 0x06
+#define RF_MARCSTATE_REGON 0x07
+#define RF_MARCSTATE_STARTCAL 0x08
+#define RF_MARCSTATE_BWBOOST 0x09
+#define RF_MARCSTATE_FS_LOCK 0x0a
+#define RF_MARCSTATE_IFADCON 0x0b
+#define RF_MARCSTATE_ENDCAL 0x0c
+#define RF_MARCSTATE_RX 0x0d
+#define RF_MARCSTATE_RX_END 0x0e
+#define RF_MARCSTATE_RX_RST 0x0f
+#define RF_MARCSTATE_TXRX_SWITCH 0x10
+#define RF_MARCSTATE_RX_OVERFLOW 0x11
+#define RF_MARCSTATE_FSTXON 0x12
+#define RF_MARCSTATE_TX 0x13
+#define RF_MARCSTATE_TX_END 0x14
+#define RF_MARCSTATE_RXTX_SWITCH 0x15
+#define RF_MARCSTATE_TX_UNDERFLOW 0x16
+
+
+__xdata __at (0xdf3c) uint8_t RF_PKTSTATUS;
+#define RF_PKTSTATUS_OFF 0x3c
+
+#define RF_PKTSTATUS_CRC_OK (1 << 7)
+#define RF_PKTSTATUS_CS (1 << 6)
+#define RF_PKTSTATUS_PQT_REACHED (1 << 5)
+#define RF_PKTSTATUS_CCA (1 << 4)
+#define RF_PKTSTATUS_SFD (1 << 3)
+
+__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
+++ /dev/null
-#!/bin/sh
-HEADER=$1
-MEM=$2
-
-HEADER_STACK=`awk '/#define AO_STACK_START/ {print strtonum($3)}' $HEADER`
-MEM_STACK=`awk '/Stack starts at/ {print strtonum ($4)}' $MEM`
-
-if [ "$HEADER_STACK" -lt "$MEM_STACK" ]; then
- echo $MEM_STACK | awk '{ printf ("Set AO_STACK_START to at least 0x%x\n", $1); }'
- exit 1
-else
- exit 0
-fi
--- /dev/null
+/*max error 3.197865153490684 at 0.782%. Average error 0.260150920474668*/
+#define NALT 129
+#define ALT_FRAC_BITS 8
+ 15835, /* 10.56 kPa 0.000% */
+ 15332, /* 11.42 kPa 0.781% */
+ 14868, /* 12.29 kPa 1.563% */
+ 14435, /* 13.16 kPa 2.344% */
+ 14030, /* 14.02 kPa 3.125% */
+ 13649, /* 14.90 kPa 3.906% */
+ 13290, /* 15.76 kPa 4.688% */
+ 12950, /* 16.63 kPa 5.469% */
+ 12627, /* 17.50 kPa 6.250% */
+ 12320, /* 18.37 kPa 7.031% */
+ 12027, /* 19.24 kPa 7.813% */
+ 11747, /* 20.10 kPa 8.594% */
+ 11479, /* 20.97 kPa 9.375% */
+ 11222, /* 21.84 kPa 10.156% */
+ 10975, /* 22.71 kPa 10.938% */
+ 10736, /* 23.58 kPa 11.719% */
+ 10504, /* 24.44 kPa 12.500% */
+ 10278, /* 25.31 kPa 13.281% */
+ 10059, /* 26.18 kPa 14.063% */
+ 9846, /* 27.05 kPa 14.844% */
+ 9638, /* 27.91 kPa 15.625% */
+ 9435, /* 28.78 kPa 16.406% */
+ 9237, /* 29.65 kPa 17.188% */
+ 9044, /* 30.52 kPa 17.969% */
+ 8855, /* 31.39 kPa 18.750% */
+ 8670, /* 32.26 kPa 19.531% */
+ 8490, /* 33.13 kPa 20.313% */
+ 8313, /* 33.99 kPa 21.094% */
+ 8140, /* 34.86 kPa 21.875% */
+ 7970, /* 35.73 kPa 22.656% */
+ 7803, /* 36.60 kPa 23.438% */
+ 7640, /* 37.47 kPa 24.219% */
+ 7480, /* 38.33 kPa 25.000% */
+ 7322, /* 39.20 kPa 25.781% */
+ 7168, /* 40.07 kPa 26.563% */
+ 7016, /* 40.94 kPa 27.344% */
+ 6867, /* 41.80 kPa 28.125% */
+ 6720, /* 42.67 kPa 28.906% */
+ 6575, /* 43.54 kPa 29.688% */
+ 6433, /* 44.41 kPa 30.469% */
+ 6294, /* 45.28 kPa 31.250% */
+ 6156, /* 46.15 kPa 32.031% */
+ 6020, /* 47.01 kPa 32.813% */
+ 5887, /* 47.88 kPa 33.594% */
+ 5755, /* 48.75 kPa 34.375% */
+ 5625, /* 49.62 kPa 35.156% */
+ 5497, /* 50.49 kPa 35.938% */
+ 5371, /* 51.35 kPa 36.719% */
+ 5247, /* 52.22 kPa 37.500% */
+ 5124, /* 53.09 kPa 38.281% */
+ 5003, /* 53.96 kPa 39.063% */
+ 4883, /* 54.83 kPa 39.844% */
+ 4765, /* 55.69 kPa 40.625% */
+ 4648, /* 56.56 kPa 41.406% */
+ 4533, /* 57.43 kPa 42.188% */
+ 4419, /* 58.30 kPa 42.969% */
+ 4307, /* 59.17 kPa 43.750% */
+ 4196, /* 60.03 kPa 44.531% */
+ 4086, /* 60.90 kPa 45.313% */
+ 3977, /* 61.77 kPa 46.094% */
+ 3870, /* 62.63 kPa 46.875% */
+ 3764, /* 63.51 kPa 47.656% */
+ 3659, /* 64.38 kPa 48.438% */
+ 3555, /* 65.24 kPa 49.219% */
+ 3453, /* 66.11 kPa 50.000% */
+ 3351, /* 66.98 kPa 50.781% */
+ 3250, /* 67.85 kPa 51.563% */
+ 3151, /* 68.72 kPa 52.344% */
+ 3052, /* 69.58 kPa 53.125% */
+ 2955, /* 70.45 kPa 53.906% */
+ 2858, /* 71.32 kPa 54.688% */
+ 2763, /* 72.19 kPa 55.469% */
+ 2668, /* 73.06 kPa 56.250% */
+ 2574, /* 73.92 kPa 57.031% */
+ 2482, /* 74.79 kPa 57.813% */
+ 2390, /* 75.66 kPa 58.594% */
+ 2298, /* 76.52 kPa 59.375% */
+ 2208, /* 77.40 kPa 60.156% */
+ 2119, /* 78.26 kPa 60.938% */
+ 2030, /* 79.13 kPa 61.719% */
+ 1942, /* 80.00 kPa 62.500% */
+ 1855, /* 80.87 kPa 63.281% */
+ 1769, /* 81.74 kPa 64.063% */
+ 1683, /* 82.60 kPa 64.844% */
+ 1598, /* 83.47 kPa 65.625% */
+ 1514, /* 84.34 kPa 66.406% */
+ 1430, /* 85.21 kPa 67.188% */
+ 1347, /* 86.08 kPa 67.969% */
+ 1265, /* 86.94 kPa 68.750% */
+ 1184, /* 87.81 kPa 69.531% */
+ 1103, /* 88.68 kPa 70.313% */
+ 1023, /* 89.55 kPa 71.094% */
+ 943, /* 90.41 kPa 71.875% */
+ 864, /* 91.28 kPa 72.656% */
+ 786, /* 92.15 kPa 73.438% */
+ 708, /* 93.02 kPa 74.219% */
+ 631, /* 93.89 kPa 75.000% */
+ 554, /* 94.76 kPa 75.781% */
+ 478, /* 95.63 kPa 76.563% */
+ 403, /* 96.49 kPa 77.344% */
+ 328, /* 97.36 kPa 78.125% */
+ 254, /* 98.23 kPa 78.906% */
+ 180, /* 99.10 kPa 79.688% */
+ 106, /* 99.97 kPa 80.469% */
+ 34, /* 100.83 kPa 81.250% */
+ -39, /* 101.70 kPa 82.031% */
+ -111, /* 102.57 kPa 82.813% */
+ -182, /* 103.44 kPa 83.594% */
+ -253, /* 104.30 kPa 84.375% */
+ -323, /* 105.17 kPa 85.156% */
+ -393, /* 106.04 kPa 85.938% */
+ -462, /* 106.91 kPa 86.719% */
+ -531, /* 107.78 kPa 87.500% */
+ -600, /* 108.65 kPa 88.281% */
+ -668, /* 109.51 kPa 89.063% */
+ -736, /* 110.38 kPa 89.844% */
+ -803, /* 111.25 kPa 90.625% */
+ -870, /* 112.12 kPa 91.406% */
+ -936, /* 112.99 kPa 92.188% */
+ -1002, /* 113.85 kPa 92.969% */
+ -1068, /* 114.72 kPa 93.750% */
+ -1133, /* 115.59 kPa 94.531% */
+ -1198, /* 116.46 kPa 95.313% */
+ -1262, /* 117.33 kPa 96.094% */
+ -1326, /* 118.19 kPa 96.875% */
+ -1389, /* 119.06 kPa 97.656% */
+ -1453, /* 119.93 kPa 98.438% */
+ -1516, /* 120.80 kPa 99.219% */
+ -1578, /* 121.67 kPa 100.000% */
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_H_
+#define _AO_H_
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include "ao_pins.h"
+#include <ao_arch.h>
+
+#define TRUE 1
+#define FALSE 0
+
+/* Convert a __data pointer into an __xdata pointer */
+#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 */
+ 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 */
+};
+
+extern __xdata struct ao_task *__data ao_cur_task;
+
+#define AO_NUM_TASKS 16 /* maximum number of tasks */
+#define AO_NO_TASK 0 /* no task id */
+
+/*
+ ao_task.c
+ */
+
+/* Suspend the current task until wchan is awoken.
+ * returns:
+ * 0 on normal wake
+ * 1 on alarm
+ */
+uint8_t
+ao_sleep(__xdata void *wchan);
+
+/* Wake all tasks sleeping on wchan */
+void
+ao_wakeup(__xdata void *wchan);
+
+/* set an alarm to go off in 'delay' ticks */
+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) ao_arch_naked_declare;
+
+/* Add a task to the run queue */
+void
+ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant;
+
+/* Terminate the current task */
+void
+ao_exit(void);
+
+/* Dump task info to console */
+void
+ao_task_info(void);
+
+/* Start the scheduler. This will not return */
+void
+ao_start_scheduler(void);
+
+/*
+ * ao_panic.c
+ */
+
+#define AO_PANIC_NO_TASK 1 /* AO_NUM_TASKS is not large enough */
+#define AO_PANIC_DMA 2 /* Attempt to start DMA while active */
+#define AO_PANIC_MUTEX 3 /* Mis-using mutex API */
+#define AO_PANIC_EE 4 /* Mis-using eeprom API */
+#define AO_PANIC_LOG 5 /* Failing to read/write log data */
+#define AO_PANIC_CMD 6 /* Too many command sets registered */
+#define AO_PANIC_STDIO 7 /* Too many stdio handlers registered */
+#define AO_PANIC_REBOOT 8 /* Reboot failed */
+#define AO_PANIC_FLASH 9 /* Invalid flash part (or wrong blocksize) */
+#define AO_PANIC_USB 10 /* Trying to send USB packet while busy */
+#define AO_PANIC_BT 11 /* Communications with bluetooth device failed */
+
+/* Stop the operating system, beeping and blinking the reason */
+void
+ao_panic(uint8_t reason);
+
+/*
+ * ao_timer.c
+ */
+
+/* Our timer runs at 100Hz */
+#define AO_HERTZ 100
+#define AO_MS_TO_TICKS(ms) ((ms) / (1000 / AO_HERTZ))
+#define AO_SEC_TO_TICKS(s) ((s) * AO_HERTZ)
+
+/* Returns the current time in ticks */
+uint16_t
+ao_time(void);
+
+/* Suspend the current task until ticks time has passed */
+void
+ao_delay(uint16_t ticks);
+
+/* Set the ADC interval */
+void
+ao_timer_set_adc_interval(uint8_t interval) __critical;
+
+/* Timer interrupt */
+void
+ao_timer_isr(void) ao_arch_interrupt(9);
+
+/* Initialize the timer */
+void
+ao_timer_init(void);
+
+/* Initialize the hardware clock. Must be called first */
+void
+ao_clock_init(void);
+
+/*
+ * One set of samples read from the A/D converter or telemetry
+ */
+
+#if HAS_ADC
+
+/*
+ * ao_adc.c
+ */
+
+#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1))
+#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1))
+
+
+/*
+ * A/D data is stored in a ring, with the next sample to be written
+ * at ao_adc_head
+ */
+extern volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING];
+extern volatile __data uint8_t ao_adc_head;
+#if HAS_ACCEL_REF
+extern volatile __xdata uint16_t ao_accel_ref[AO_ADC_RING];
+#endif
+
+/* Trigger a conversion sequence (called from the timer interrupt) */
+void
+ao_adc_poll(void);
+
+/* Suspend the current task until another A/D sample is converted */
+void
+ao_adc_sleep(void);
+
+/* Get a copy of the last complete A/D sample set */
+void
+ao_adc_get(__xdata struct ao_adc *packet);
+
+/* The A/D interrupt handler */
+
+void
+ao_adc_isr(void) ao_arch_interrupt(1);
+
+/* Initialize the A/D converter */
+void
+ao_adc_init(void);
+
+#endif /* HAS_ADC */
+
+/*
+ * ao_beep.c
+ */
+
+/*
+ * Various pre-defined beep frequencies
+ *
+ * frequency = 1/2 (24e6/32) / beep
+ */
+
+#define AO_BEEP_LOW 150 /* 2500Hz */
+#define AO_BEEP_MID 94 /* 3989Hz */
+#define AO_BEEP_HIGH 75 /* 5000Hz */
+#define AO_BEEP_OFF 0 /* off */
+
+#define AO_BEEP_g 240 /* 1562.5Hz */
+#define AO_BEEP_gs 227 /* 1652Hz (1655Hz) */
+#define AO_BEEP_aa 214 /* 1752Hz (1754Hz) */
+#define AO_BEEP_bbf 202 /* 1856Hz (1858Hz) */
+#define AO_BEEP_bb 190 /* 1974Hz (1969Hz) */
+#define AO_BEEP_cc 180 /* 2083Hz (2086Hz) */
+#define AO_BEEP_ccs 170 /* 2205Hz (2210Hz) */
+#define AO_BEEP_dd 160 /* 2344Hz (2341Hz) */
+#define AO_BEEP_eef 151 /* 2483Hz (2480Hz) */
+#define AO_BEEP_ee 143 /* 2622Hz (2628Hz) */
+#define AO_BEEP_ff 135 /* 2778Hz (2784Hz) */
+#define AO_BEEP_ffs 127 /* 2953Hz (2950Hz) */
+#define AO_BEEP_gg 120 /* 3125Hz */
+#define AO_BEEP_ggs 113 /* 3319Hz (3311Hz) */
+#define AO_BEEP_aaa 107 /* 3504Hz (3508Hz) */
+#define AO_BEEP_bbbf 101 /* 3713Hz (3716Hz) */
+#define AO_BEEP_bbb 95 /* 3947Hz (3937Hz) */
+#define AO_BEEP_ccc 90 /* 4167Hz (4171Hz) */
+#define AO_BEEP_cccs 85 /* 4412Hz (4419Hz) */
+#define AO_BEEP_ddd 80 /* 4688Hz (4682Hz) */
+#define AO_BEEP_eeef 76 /* 4934Hz (4961Hz) */
+#define AO_BEEP_eee 71 /* 5282Hz (5256Hz) */
+#define AO_BEEP_fff 67 /* 5597Hz (5568Hz) */
+#define AO_BEEP_fffs 64 /* 5859Hz (5899Hz) */
+#define AO_BEEP_ggg 60 /* 6250Hz */
+
+/* Set the beeper to the specified tone */
+void
+ao_beep(uint8_t beep);
+
+/* Turn on the beeper for the specified time */
+void
+ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant;
+
+/* Initialize the beeper */
+void
+ao_beep_init(void);
+
+/*
+ * ao_led.c
+ */
+
+#define AO_LED_NONE 0
+
+/* Turn on the specified LEDs */
+void
+ao_led_on(uint8_t colors);
+
+/* Turn off the specified LEDs */
+void
+ao_led_off(uint8_t colors);
+
+/* Set all of the LEDs to the specified state */
+void
+ao_led_set(uint8_t colors);
+
+/* Toggle the specified LEDs */
+void
+ao_led_toggle(uint8_t colors);
+
+/* Turn on the specified LEDs for the indicated interval */
+void
+ao_led_for(uint8_t colors, uint16_t ticks) __reentrant;
+
+/* Initialize the LEDs */
+void
+ao_led_init(uint8_t enable);
+
+/*
+ * ao_usb.c
+ */
+
+/* Put one character to the USB output queue */
+void
+ao_usb_putchar(char c);
+
+/* Get one character from the USB input queue */
+char
+ao_usb_getchar(void);
+
+/* Poll for a charcter on the USB input queue.
+ * returns AO_READ_AGAIN if none are available
+ */
+char
+ao_usb_pollchar(void);
+
+/* Flush the USB output queue */
+void
+ao_usb_flush(void);
+
+#if HAS_USB
+/* USB interrupt handler */
+void
+ao_usb_isr(void) ao_arch_interrupt(6);
+#endif
+
+/* Enable the USB controller */
+void
+ao_usb_enable(void);
+
+/* Disable the USB controller */
+void
+ao_usb_disable(void);
+
+/* Initialize the USB system */
+void
+ao_usb_init(void);
+
+#if HAS_USB
+extern __code __at (0x00aa) uint8_t ao_usb_descriptors [];
+#endif
+
+/*
+ * ao_cmd.c
+ */
+
+enum ao_cmd_status {
+ ao_cmd_success = 0,
+ ao_cmd_lex_error = 1,
+ ao_cmd_syntax_error = 2,
+};
+
+extern __pdata uint16_t ao_cmd_lex_i;
+extern __pdata uint32_t ao_cmd_lex_u32;
+extern __pdata char ao_cmd_lex_c;
+extern __pdata enum ao_cmd_status ao_cmd_status;
+
+void
+ao_cmd_lex(void);
+
+void
+ao_cmd_put8(uint8_t v);
+
+void
+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);
+
+void
+ao_cmd_decimal(void);
+
+uint8_t
+ao_match_word(__code char *word);
+
+struct ao_cmds {
+ void (*func)(void);
+ __code char *help;
+};
+
+void
+ao_cmd_register(__code struct ao_cmds *cmds);
+
+void
+ao_cmd_init(void);
+
+#if HAS_CMD_FILTER
+/*
+ * Provided by an external module to filter raw command lines
+ */
+uint8_t
+ao_cmd_filter(void);
+#endif
+
+/*
+ * ao_dma.c
+ */
+
+/* Allocate a DMA channel. the 'done' parameter will be set when the
+ * dma is finished and will be used to wakeup any waiters
+ */
+
+uint8_t
+ao_dma_alloc(__xdata uint8_t * done);
+
+/* Setup a DMA channel */
+void
+ao_dma_set_transfer(uint8_t id,
+ void __xdata *srcaddr,
+ void __xdata *dstaddr,
+ uint16_t count,
+ uint8_t cfg0,
+ uint8_t cfg1);
+
+/* Start a DMA channel */
+void
+ao_dma_start(uint8_t id);
+
+/* Manually trigger a DMA channel */
+void
+ao_dma_trigger(uint8_t id);
+
+/* Abort a running DMA transfer */
+void
+ao_dma_abort(uint8_t id);
+
+/* DMA interrupt routine */
+void
+ao_dma_isr(void) ao_arch_interrupt(8);
+
+/*
+ * ao_mutex.c
+ */
+
+void
+ao_mutex_get(__xdata uint8_t *ao_mutex) __reentrant;
+
+void
+ao_mutex_put(__xdata uint8_t *ao_mutex) __reentrant;
+
+/*
+ * Storage interface, provided by one of the eeprom or flash
+ * drivers
+ */
+
+/* Total bytes of available storage */
+extern __pdata uint32_t ao_storage_total;
+
+/* Block size - device is erased in these units. At least 256 bytes */
+extern __pdata uint32_t ao_storage_block;
+
+/* Byte offset of config block. Will be ao_storage_block bytes long */
+extern __pdata uint32_t ao_storage_config;
+
+/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */
+extern __pdata uint16_t ao_storage_unit;
+
+#define AO_STORAGE_ERASE_LOG (ao_storage_config + AO_CONFIG_MAX_SIZE)
+
+/* Initialize above values. Can only be called once the OS is running */
+void
+ao_storage_setup(void) __reentrant;
+
+/* Write data. Returns 0 on failure, 1 on success */
+uint8_t
+ao_storage_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant;
+
+/* Read data. Returns 0 on failure, 1 on success */
+uint8_t
+ao_storage_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant;
+
+/* Erase a block of storage. This always clears ao_storage_block bytes */
+uint8_t
+ao_storage_erase(uint32_t pos) __reentrant;
+
+/* Flush any pending writes to stable storage */
+void
+ao_storage_flush(void) __reentrant;
+
+/* Initialize the storage code */
+void
+ao_storage_init(void);
+
+/*
+ * Low-level functions wrapped by ao_storage.c
+ */
+
+/* Read data within a storage unit */
+uint8_t
+ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant;
+
+/* Write data within a storage unit */
+uint8_t
+ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant;
+
+/* Initialize low-level device bits */
+void
+ao_storage_device_init(void);
+
+/* Print out information about flash chips */
+void
+ao_storage_device_info(void) __reentrant;
+
+/*
+ * ao_log.c
+ */
+
+/* We record flight numbers in the first record of
+ * the log. Tasks may wait for this to be initialized
+ * by sleeping on this variable.
+ */
+extern __xdata uint16_t ao_flight_number;
+
+extern __pdata uint32_t ao_log_current_pos;
+extern __pdata uint32_t ao_log_end_pos;
+extern __pdata uint32_t ao_log_start_pos;
+extern __xdata uint8_t ao_log_running;
+extern __pdata enum flight_state ao_log_state;
+
+/* required functions from the underlying log system */
+
+#define AO_LOG_FORMAT_UNKNOWN 0 /* unknown; altosui will have to guess */
+#define AO_LOG_FORMAT_FULL 1 /* 8 byte typed log records */
+#define AO_LOG_FORMAT_TINY 2 /* two byte state/baro records */
+#define AO_LOG_FORMAT_TELEMETRY 3 /* 32 byte ao_telemetry records */
+#define AO_LOG_FORMAT_TELESCIENCE 4 /* 32 byte typed telescience records */
+#define AO_LOG_FORMAT_NONE 127 /* No log at all */
+
+extern __code uint8_t ao_log_format;
+
+/* Return the flight number from the given log slot, 0 if none */
+uint16_t
+ao_log_flight(uint8_t slot);
+
+/* Flush the log */
+void
+ao_log_flush(void);
+
+/* Logging thread main routine */
+void
+ao_log(void);
+
+/* functions provided in ao_log.c */
+
+/* Figure out the current flight number */
+void
+ao_log_scan(void) __reentrant;
+
+/* Return the position of the start of the given log slot */
+uint32_t
+ao_log_pos(uint8_t slot);
+
+/* Start logging to eeprom */
+void
+ao_log_start(void);
+
+/* Stop logging */
+void
+ao_log_stop(void);
+
+/* Initialize the logging system */
+void
+ao_log_init(void);
+
+/* Write out the current flight number to the erase log */
+void
+ao_log_write_erase(uint8_t pos);
+
+/* Returns true if there are any logs stored in eeprom */
+uint8_t
+ao_log_present(void);
+
+/* Returns true if there is no more storage space available */
+uint8_t
+ao_log_full(void);
+
+/*
+ * ao_log_big.c
+ */
+
+/*
+ * The data log is recorded in the eeprom as a sequence
+ * of data packets.
+ *
+ * Each packet starts with a 4-byte header that has the
+ * packet type, the packet checksum and the tick count. Then
+ * they all contain 2 16 bit values which hold packet-specific
+ * data.
+ *
+ * For each flight, the first packet
+ * is FLIGHT packet, indicating the serial number of the
+ * device and a unique number marking the number of flights
+ * recorded by this device.
+ *
+ * During flight, data from the accelerometer and barometer
+ * are recorded in SENSOR packets, using the raw 16-bit values
+ * read from the A/D converter.
+ *
+ * Also during flight, but at a lower rate, the deployment
+ * sensors are recorded in DEPLOY packets. The goal here is to
+ * detect failure in the deployment circuits.
+ *
+ * STATE packets hold state transitions as the flight computer
+ * transitions through different stages of the flight.
+ */
+#define AO_LOG_FLIGHT 'F'
+#define AO_LOG_SENSOR 'A'
+#define AO_LOG_TEMP_VOLT 'T'
+#define AO_LOG_DEPLOY 'D'
+#define AO_LOG_STATE 'S'
+#define AO_LOG_GPS_TIME 'G'
+#define AO_LOG_GPS_LAT 'N'
+#define AO_LOG_GPS_LON 'W'
+#define AO_LOG_GPS_ALT 'H'
+#define AO_LOG_GPS_SAT 'V'
+#define AO_LOG_GPS_DATE 'Y'
+
+#define AO_LOG_POS_NONE (~0UL)
+
+struct ao_log_record {
+ char type;
+ uint8_t csum;
+ uint16_t tick;
+ union {
+ struct {
+ int16_t ground_accel;
+ uint16_t flight;
+ } flight;
+ struct {
+ int16_t accel;
+ int16_t pres;
+ } sensor;
+ struct {
+ int16_t temp;
+ int16_t v_batt;
+ } temp_volt;
+ struct {
+ int16_t drogue;
+ int16_t main;
+ } deploy;
+ struct {
+ uint16_t state;
+ uint16_t reason;
+ } state;
+ struct {
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
+ uint8_t flags;
+ } gps_time;
+ int32_t gps_latitude;
+ int32_t gps_longitude;
+ struct {
+ int16_t altitude;
+ uint16_t unused;
+ } gps_altitude;
+ struct {
+ uint16_t svid;
+ uint8_t unused;
+ uint8_t c_n;
+ } gps_sat;
+ struct {
+ uint8_t year;
+ uint8_t month;
+ uint8_t day;
+ uint8_t extra;
+ } gps_date;
+ struct {
+ uint16_t d0;
+ uint16_t d1;
+ } anon;
+ } u;
+};
+
+/* Write a record to the eeprom log */
+uint8_t
+ao_log_data(__xdata struct ao_log_record *log) __reentrant;
+
+/*
+ * ao_flight.c
+ */
+
+enum ao_flight_state {
+ ao_flight_startup = 0,
+ ao_flight_idle = 1,
+ ao_flight_pad = 2,
+ ao_flight_boost = 3,
+ ao_flight_fast = 4,
+ ao_flight_coast = 5,
+ ao_flight_drogue = 6,
+ ao_flight_main = 7,
+ ao_flight_landed = 8,
+ ao_flight_invalid = 9
+};
+
+extern __pdata enum ao_flight_state ao_flight_state;
+
+extern __pdata uint16_t ao_launch_time;
+extern __pdata uint8_t ao_flight_force_idle;
+
+/* Flight thread */
+void
+ao_flight(void);
+
+/* Initialize flight thread */
+void
+ao_flight_init(void);
+
+/*
+ * ao_flight_nano.c
+ */
+
+void
+ao_flight_nano_init(void);
+
+/*
+ * ao_sample.c
+ */
+
+/*
+ * Barometer calibration
+ *
+ * We directly sample the barometer. The specs say:
+ *
+ * Pressure range: 15-115 kPa
+ * Voltage at 115kPa: 2.82
+ * Output scale: 27mV/kPa
+ *
+ * If we want to detect launch with the barometer, we need
+ * a large enough bump to not be fooled by noise. At typical
+ * launch elevations (0-2000m), a 200Pa pressure change cooresponds
+ * to about a 20m elevation change. This is 5.4mV, or about 3LSB.
+ * As all of our calculations are done in 16 bits, we'll actually see a change
+ * of 16 times this though
+ *
+ * 27 mV/kPa * 32767 / 3300 counts/mV = 268.1 counts/kPa
+ */
+
+/* Accelerometer calibration
+ *
+ * We're sampling the accelerometer through a resistor divider which
+ * consists of 5k and 10k resistors. This multiplies the values by 2/3.
+ * That goes into the cc1111 A/D converter, which is running at 11 bits
+ * of precision with the bits in the MSB of the 16 bit value. Only positive
+ * values are used, so values should range from 0-32752 for 0-3.3V. The
+ * specs say we should see 40mV/g (uncalibrated), multiply by 2/3 for what
+ * the A/D converter sees (26.67 mV/g). We should see 32752/3300 counts/mV,
+ * for a final computation of:
+ *
+ * 26.67 mV/g * 32767/3300 counts/mV = 264.8 counts/g
+ *
+ * Zero g was measured at 16000 (we would expect 16384).
+ * Note that this value is only require to tell if the
+ * rocket is standing upright. Once that is determined,
+ * the value of the accelerometer is averaged for 100 samples
+ * to find the resting accelerometer value, which is used
+ * for all further flight computations
+ */
+
+#define GRAVITY 9.80665
+
+/*
+ * Above this height, the baro sensor doesn't work
+ */
+#define AO_MAX_BARO_HEIGHT 12000
+
+/*
+ * Above this speed, baro measurements are unreliable
+ */
+#define AO_MAX_BARO_SPEED 200
+
+#define ACCEL_NOSE_UP (ao_accel_2g >> 2)
+
+/*
+ * Speed and acceleration are scaled by 16 to provide a bit more
+ * resolution while still having reasonable range. Note that this
+ * limits speed to 2047m/s (around mach 6) and acceleration to
+ * 2047m/s² (over 200g)
+ */
+
+#define AO_M_TO_HEIGHT(m) ((int16_t) (m))
+#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16))
+#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16))
+
+extern __pdata uint16_t ao_sample_tick; /* time of last data */
+extern __pdata int16_t ao_sample_pres; /* most recent pressure sensor reading */
+extern __pdata int16_t ao_sample_alt; /* MSL of ao_sample_pres */
+extern __pdata int16_t ao_sample_height; /* AGL of ao_sample_pres */
+extern __data uint8_t ao_sample_adc; /* Ring position of last processed sample */
+
+#if HAS_ACCEL
+extern __pdata int16_t ao_sample_accel; /* most recent accel sensor reading */
+#endif
+
+extern __pdata int16_t ao_ground_pres; /* startup pressure */
+extern __pdata int16_t ao_ground_height; /* MSL of ao_ground_pres */
+
+#if HAS_ACCEL
+extern __pdata int16_t ao_ground_accel; /* startup acceleration */
+extern __pdata int16_t ao_accel_2g; /* factory accel calibration */
+extern __pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */
+#endif
+
+void ao_sample_init(void);
+
+/* returns FALSE in preflight mode, TRUE in flight mode */
+uint8_t ao_sample(void);
+
+/*
+ * ao_kalman.c
+ */
+
+#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5))
+#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5))
+#define from_fix(x) ((x) >> 16)
+
+extern __pdata int16_t ao_height; /* meters */
+extern __pdata int16_t ao_speed; /* m/s * 16 */
+extern __pdata int16_t ao_accel; /* m/s² * 16 */
+extern __pdata int16_t ao_max_height; /* max of ao_height */
+extern __pdata int16_t ao_avg_height; /* running average of height */
+
+extern __pdata int16_t ao_error_h;
+extern __pdata int16_t ao_error_h_sq_avg;
+
+#if HAS_ACCEL
+extern __pdata int16_t ao_error_a;
+#endif
+
+void ao_kalman(void);
+
+/*
+ * ao_report.c
+ */
+
+void
+ao_report_init(void);
+
+/*
+ * ao_convert.c
+ *
+ * Given raw data, convert to SI units
+ */
+
+/* pressure from the sensor to altitude in meters */
+int16_t
+ao_pres_to_altitude(int16_t pres) __reentrant;
+
+int16_t
+ao_altitude_to_pres(int16_t alt) __reentrant;
+
+int16_t
+ao_temp_to_dC(int16_t temp) __reentrant;
+
+/*
+ * ao_dbg.c
+ *
+ * debug another telemetrum board
+ */
+
+/* Send a byte to the dbg target */
+void
+ao_dbg_send_byte(uint8_t byte);
+
+/* Receive a byte from the dbg target */
+uint8_t
+ao_dbg_recv_byte(void);
+
+/* Start a bulk transfer to/from dbg target memory */
+void
+ao_dbg_start_transfer(uint16_t addr);
+
+/* End a bulk transfer to/from dbg target memory */
+void
+ao_dbg_end_transfer(void);
+
+/* Write a byte to dbg target memory */
+void
+ao_dbg_write_byte(uint8_t byte);
+
+/* Read a byte from dbg target memory */
+uint8_t
+ao_dbg_read_byte(void);
+
+/* Enable dbg mode, switching use of the pins */
+void
+ao_dbg_debug_mode(void);
+
+/* Reset the dbg target */
+void
+ao_dbg_reset(void);
+
+void
+ao_dbg_init(void);
+
+/*
+ * ao_serial.c
+ */
+
+#ifndef HAS_SERIAL_1
+#error Please define HAS_SERIAL_1
+#endif
+
+#if HAS_SERIAL_1
+#ifndef USE_SERIAL_STDIN
+#error Please define USE_SERIAL_STDIN
+#endif
+
+void
+ao_serial_rx1_isr(void) ao_arch_interrupt(3);
+
+void
+ao_serial_tx1_isr(void) ao_arch_interrupt(14);
+
+char
+ao_serial_getchar(void) __critical;
+
+#if USE_SERIAL_STDIN
+char
+ao_serial_pollchar(void) __critical;
+
+void
+ao_serial_set_stdin(uint8_t stdin);
+#endif
+
+void
+ao_serial_putchar(char c) __critical;
+
+void
+ao_serial_drain(void) __critical;
+
+#define AO_SERIAL_SPEED_4800 0
+#define AO_SERIAL_SPEED_9600 1
+#define AO_SERIAL_SPEED_19200 2
+#define AO_SERIAL_SPEED_57600 3
+
+void
+ao_serial_set_speed(uint8_t speed);
+
+void
+ao_serial_init(void);
+#endif
+
+/*
+ * ao_spi.c
+ */
+
+extern __xdata uint8_t ao_spi_mutex;
+
+#define ao_spi_get_mask(reg,mask) do {\
+ ao_mutex_get(&ao_spi_mutex); \
+ (reg) &= ~(mask); \
+ } while (0)
+
+#define ao_spi_put_mask(reg,mask) do { \
+ (reg) |= (mask); \
+ ao_mutex_put(&ao_spi_mutex); \
+ } while (0)
+
+#define ao_spi_get_bit(bit) do {\
+ ao_mutex_get(&ao_spi_mutex); \
+ (bit) = 0; \
+ } while (0)
+
+#define ao_spi_put_bit(bit) do { \
+ (bit) = 1; \
+ ao_mutex_put(&ao_spi_mutex); \
+ } while (0)
+
+/*
+ * The SPI mutex must be held to call either of these
+ * functions -- this mutex covers the entire SPI operation,
+ * from chip select low to chip select high
+ */
+
+void
+ao_spi_send(void __xdata *block, uint16_t len) __reentrant;
+
+void
+ao_spi_recv(void __xdata *block, uint16_t len) __reentrant;
+
+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
+#define AO_MAX_VERSION 8
+#define AO_MAX_TELEMETRY 128
+
+struct ao_telemetry_generic {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+ uint8_t payload[27]; /* 5 */
+ /* 32 */
+};
+
+#define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01
+#define AO_TELEMETRY_SENSOR_TELEMINI 0x02
+#define AO_TELEMETRY_SENSOR_TELENANO 0x03
+
+struct ao_telemetry_sensor {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+
+ uint8_t state; /* 5 flight state */
+ int16_t accel; /* 6 accelerometer (TM only) */
+ int16_t pres; /* 8 pressure sensor */
+ int16_t temp; /* 10 temperature sensor */
+ int16_t v_batt; /* 12 battery voltage */
+ int16_t sense_d; /* 14 drogue continuity sense (TM/Tm) */
+ int16_t sense_m; /* 16 main continuity sense (TM/Tm) */
+
+ int16_t acceleration; /* 18 m/s² * 16 */
+ int16_t speed; /* 20 m/s * 16 */
+ int16_t height; /* 22 m */
+
+ int16_t ground_pres; /* 24 average pres on pad */
+ int16_t ground_accel; /* 26 average accel on pad */
+ int16_t accel_plus_g; /* 28 accel calibration at +1g */
+ int16_t accel_minus_g; /* 30 accel calibration at -1g */
+ /* 32 */
+};
+
+#define AO_TELEMETRY_CONFIGURATION 0x04
+
+struct ao_telemetry_configuration {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+
+ uint8_t device; /* 5 device type */
+ uint16_t flight; /* 6 flight number */
+ uint8_t config_major; /* 8 Config major version */
+ uint8_t config_minor; /* 9 Config minor version */
+ uint16_t apogee_delay; /* 10 Apogee deploy delay in seconds */
+ uint16_t main_deploy; /* 12 Main deploy alt in meters */
+ uint16_t flight_log_max; /* 14 Maximum flight log size in kB */
+ char callsign[AO_MAX_CALLSIGN]; /* 16 Radio operator identity */
+ char version[AO_MAX_VERSION]; /* 24 Software version */
+ /* 32 */
+};
+
+#define AO_TELEMETRY_LOCATION 0x05
+
+#define AO_GPS_MODE_NOT_VALID 'N'
+#define AO_GPS_MODE_AUTONOMOUS 'A'
+#define AO_GPS_MODE_DIFFERENTIAL 'D'
+#define AO_GPS_MODE_ESTIMATED 'E'
+#define AO_GPS_MODE_MANUAL 'M'
+#define AO_GPS_MODE_SIMULATED 'S'
+
+struct ao_telemetry_location {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+
+ uint8_t flags; /* 5 Number of sats and other flags */
+ int16_t altitude; /* 6 GPS reported altitude (m) */
+ int32_t latitude; /* 8 latitude (degrees * 10⁷) */
+ int32_t longitude; /* 12 longitude (degrees * 10⁷) */
+ uint8_t year; /* 16 (- 2000) */
+ uint8_t month; /* 17 (1-12) */
+ uint8_t day; /* 18 (1-31) */
+ uint8_t hour; /* 19 (0-23) */
+ uint8_t minute; /* 20 (0-59) */
+ uint8_t second; /* 21 (0-59) */
+ uint8_t pdop; /* 22 (m * 5) */
+ uint8_t hdop; /* 23 (m * 5) */
+ uint8_t vdop; /* 24 (m * 5) */
+ uint8_t mode; /* 25 */
+ uint16_t ground_speed; /* 26 cm/s */
+ int16_t climb_rate; /* 28 cm/s */
+ uint8_t course; /* 30 degrees / 2 */
+ uint8_t unused[1]; /* 31 */
+ /* 32 */
+};
+
+#define AO_TELEMETRY_SATELLITE 0x06
+
+struct ao_telemetry_satellite_info {
+ uint8_t svid;
+ uint8_t c_n_1;
+};
+
+struct ao_telemetry_satellite {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+ uint8_t channels; /* 5 number of reported sats */
+
+ struct ao_telemetry_satellite_info sats[12]; /* 6 */
+ uint8_t unused[2]; /* 30 */
+ /* 32 */
+};
+
+#define AO_TELEMETRY_COMPANION 0x07
+
+#define AO_COMPANION_MAX_CHANNELS 12
+
+struct ao_telemetry_companion {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+ uint8_t board_id; /* 5 */
+
+ uint8_t update_period; /* 6 */
+ uint8_t channels; /* 7 */
+ uint16_t companion_data[AO_COMPANION_MAX_CHANNELS]; /* 8 */
+ /* 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;
+ struct ao_telemetry_configuration configuration;
+ struct ao_telemetry_location location;
+ struct ao_telemetry_satellite satellite;
+ struct ao_telemetry_companion companion;
+ struct ao_telemetry_baro baro;
+};
+
+/*
+ * ao_gps.c
+ */
+
+#define AO_GPS_NUM_SAT_MASK (0xf << 0)
+#define AO_GPS_NUM_SAT_SHIFT (0)
+
+#define AO_GPS_VALID (1 << 4)
+#define AO_GPS_RUNNING (1 << 5)
+#define AO_GPS_DATE_VALID (1 << 6)
+#define AO_GPS_COURSE_VALID (1 << 7)
+
+extern __pdata uint16_t ao_gps_tick;
+extern __xdata uint8_t ao_gps_mutex;
+extern __xdata struct ao_telemetry_location ao_gps_data;
+extern __xdata struct ao_telemetry_satellite ao_gps_tracking_data;
+
+struct ao_gps_orig {
+ uint8_t year;
+ uint8_t month;
+ uint8_t day;
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
+ uint8_t flags;
+ int32_t latitude; /* degrees * 10⁷ */
+ int32_t longitude; /* degrees * 10⁷ */
+ int16_t altitude; /* m */
+ uint16_t ground_speed; /* cm/s */
+ uint8_t course; /* degrees / 2 */
+ uint8_t hdop; /* * 5 */
+ int16_t climb_rate; /* cm/s */
+ uint16_t h_error; /* m */
+ uint16_t v_error; /* m */
+};
+
+struct ao_gps_sat_orig {
+ uint8_t svid;
+ uint8_t c_n_1;
+};
+
+#define AO_MAX_GPS_TRACKING 12
+
+struct ao_gps_tracking_orig {
+ uint8_t channels;
+ struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING];
+};
+
+void
+ao_gps(void);
+
+void
+ao_gps_print(__xdata struct ao_gps_orig *gps_data);
+
+void
+ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data);
+
+void
+ao_gps_init(void);
+
+/*
+ * ao_gps_report.c
+ */
+
+void
+ao_gps_report(void);
+
+void
+ao_gps_report_init(void);
+
+/*
+ * ao_telemetry_orig.c
+ */
+
+struct ao_telemetry_orig {
+ uint16_t serial;
+ uint16_t flight;
+ uint8_t flight_state;
+ int16_t accel;
+ int16_t ground_accel;
+ union {
+ struct {
+ int16_t speed;
+ int16_t unused;
+ } k;
+ int32_t flight_vel;
+ } u;
+ int16_t height;
+ int16_t ground_pres;
+ int16_t accel_plus_g;
+ int16_t accel_minus_g;
+ struct ao_adc adc;
+ struct ao_gps_orig gps;
+ char callsign[AO_MAX_CALLSIGN];
+ struct ao_gps_tracking_orig gps_tracking;
+};
+
+struct ao_telemetry_tiny {
+ uint16_t serial;
+ uint16_t flight;
+ uint8_t flight_state;
+ int16_t height; /* AGL in meters */
+ int16_t speed; /* in m/s * 16 */
+ int16_t accel; /* in m/s² * 16 */
+ int16_t ground_pres; /* sensor units */
+ struct ao_adc adc; /* raw ADC readings */
+ char callsign[AO_MAX_CALLSIGN];
+};
+
+struct ao_telemetry_orig_recv {
+ struct ao_telemetry_orig telemetry_orig;
+ int8_t rssi;
+ uint8_t status;
+};
+
+struct ao_telemetry_tiny_recv {
+ struct ao_telemetry_tiny telemetry_tiny;
+ int8_t rssi;
+ 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);
+
+void
+ao_rdf_set(uint8_t rdf);
+
+void
+ao_telemetry_init(void);
+
+void
+ao_telemetry_orig_init(void);
+
+void
+ao_telemetry_tiny_init(void);
+
+/*
+ * ao_radio.c
+ */
+
+extern __xdata uint8_t ao_radio_dma;
+extern __xdata uint8_t ao_radio_dma_done;
+extern __xdata uint8_t ao_radio_done;
+extern __xdata uint8_t ao_radio_mutex;
+
+void
+ao_radio_general_isr(void) ao_arch_interrupt(16);
+
+void
+ao_radio_get(uint8_t len);
+
+#define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
+
+void
+ao_radio_set_packet(void);
+
+void
+ao_radio_send(__xdata void *data, uint8_t size) __reentrant;
+
+uint8_t
+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(uint8_t pkt_len);
+
+void
+ao_radio_rdf_abort(void);
+
+void
+ao_radio_idle(void);
+
+void
+ao_radio_init(void);
+
+/*
+ * ao_monitor.c
+ */
+
+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);
+
+#define AO_MONITORING_OFF 0
+#define AO_MONITORING_ORIG 1
+#define AO_MONITORING_TINY 2
+
+void
+ao_set_monitor(uint8_t monitoring);
+
+void
+ao_monitor_init(uint8_t led, uint8_t monitoring) __reentrant;
+
+/*
+ * ao_stdio.c
+ */
+
+#define AO_READ_AGAIN ((char) -1)
+
+struct ao_stdio {
+ char (*pollchar)(void);
+ void (*putchar)(char c) __reentrant;
+ void (*flush)(void);
+ uint8_t echo;
+};
+
+extern __xdata struct ao_stdio ao_stdios[];
+extern __pdata int8_t ao_cur_stdio;
+extern __pdata int8_t ao_num_stdios;
+
+void
+flush(void);
+
+extern __xdata uint8_t ao_stdin_ready;
+
+uint8_t
+ao_echo(void);
+
+int8_t
+ao_add_stdio(char (*pollchar)(void),
+ void (*putchar)(char) __reentrant,
+ void (*flush)(void)) __reentrant;
+
+/*
+ * ao_ignite.c
+ */
+
+enum ao_igniter {
+ ao_igniter_drogue = 0,
+ ao_igniter_main = 1
+};
+
+void
+ao_ignite(enum ao_igniter igniter);
+
+enum ao_igniter_status {
+ ao_igniter_unknown, /* unknown status (ambiguous voltage) */
+ ao_igniter_ready, /* continuity detected */
+ ao_igniter_active, /* igniter firing */
+ 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);
+
+void
+ao_igniter_init(void);
+
+/*
+ * ao_config.c
+ */
+
+#define AO_CONFIG_MAJOR 1
+#define AO_CONFIG_MINOR 9
+#define AO_AES_LEN 16
+
+struct ao_config {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t main_deploy;
+ int16_t accel_plus_g; /* changed for minor version 2 */
+ uint8_t radio_channel;
+ char callsign[AO_MAX_CALLSIGN + 1];
+ uint8_t apogee_delay; /* minor version 1 */
+ int16_t accel_minus_g; /* minor version 2 */
+ uint32_t radio_cal; /* minor version 3 */
+ uint32_t flight_log_max; /* minor version 4 */
+ uint8_t ignite_mode; /* minor version 5 */
+ 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
+#define AO_IGNITE_MODE_APOGEE 1
+#define AO_IGNITE_MODE_MAIN 2
+
+#define AO_PAD_ORIENTATION_ANTENNA_UP 0
+#define AO_PAD_ORIENTATION_ANTENNA_DOWN 1
+
+extern __xdata struct ao_config ao_config;
+
+#define AO_CONFIG_MAX_SIZE 128
+
+void
+ao_config_get(void);
+
+void
+ao_config_put(void);
+
+void
+ao_config_init(void);
+
+/*
+ * ao_rssi.c
+ */
+
+void
+ao_rssi_set(int rssi_value);
+
+void
+ao_rssi_init(uint8_t rssi_led);
+
+/*
+ * ao_product.c
+ *
+ * values which need to be defined for
+ * each instance of a product
+ */
+
+extern const char ao_version[];
+extern const char ao_manufacturer[];
+extern const char ao_product[];
+
+/*
+ * Fifos
+ */
+
+#define AO_FIFO_SIZE 32
+
+struct ao_fifo {
+ uint8_t insert;
+ uint8_t remove;
+ char fifo[AO_FIFO_SIZE];
+};
+
+#define ao_fifo_insert(f,c) do { \
+ (f).fifo[(f).insert] = (c); \
+ (f).insert = ((f).insert + 1) & (AO_FIFO_SIZE-1); \
+} while(0)
+
+#define ao_fifo_remove(f,c) do {\
+ c = (f).fifo[(f).remove]; \
+ (f).remove = ((f).remove + 1) & (AO_FIFO_SIZE-1); \
+} while(0)
+
+#define ao_fifo_full(f) ((((f).insert + 1) & (AO_FIFO_SIZE-1)) == (f).remove)
+#define ao_fifo_empty(f) ((f).insert == (f).remove)
+
+/*
+ * ao_packet.c
+ *
+ * Packet-based command interface
+ */
+
+#define AO_PACKET_MAX 64
+#define AO_PACKET_SYN (uint8_t) 0xff
+
+struct ao_packet {
+ uint8_t addr;
+ uint8_t len;
+ uint8_t seq;
+ uint8_t ack;
+ uint8_t d[AO_PACKET_MAX];
+ uint8_t callsign[AO_MAX_CALLSIGN];
+};
+
+struct ao_packet_recv {
+ struct ao_packet packet;
+ int8_t rssi;
+ uint8_t status;
+};
+
+extern __xdata struct ao_packet_recv ao_rx_packet;
+extern __xdata struct ao_packet ao_tx_packet;
+extern __xdata struct ao_task ao_packet_task;
+extern __xdata uint8_t ao_packet_enable;
+extern __xdata uint8_t ao_packet_master_sleeping;
+extern __pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used;
+
+void
+ao_packet_send(void);
+
+uint8_t
+ao_packet_recv(void);
+
+void
+ao_packet_flush(void);
+
+void
+ao_packet_putchar(char c) __reentrant;
+
+char
+ao_packet_pollchar(void) __critical;
+
+/* ao_packet_master.c */
+
+void
+ao_packet_master_init(void);
+
+/* ao_packet_slave.c */
+
+void
+ao_packet_slave_start(void);
+
+void
+ao_packet_slave_stop(void);
+
+void
+ao_packet_slave_init(uint8_t enable);
+
+/* ao_btm.c */
+
+/* If bt_link is on P2, this interrupt is shared by USB, so the USB
+ * code calls this function. Otherwise, it's a regular ISR.
+ */
+
+void
+ao_btm_isr(void)
+#if BT_LINK_ON_P1
+ __interrupt 15
+#endif
+ ;
+
+void
+ao_btm_init(void);
+
+/* ao_companion.c */
+
+#define AO_COMPANION_SETUP 1
+#define AO_COMPANION_FETCH 2
+#define AO_COMPANION_NOTIFY 3
+
+struct ao_companion_command {
+ uint8_t command;
+ uint8_t flight_state;
+ uint16_t tick;
+ uint16_t serial;
+ uint16_t flight;
+};
+
+struct ao_companion_setup {
+ uint16_t board_id;
+ uint16_t board_id_inverse;
+ uint8_t update_period;
+ uint8_t channels;
+};
+
+extern __pdata uint8_t ao_companion_running;
+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_ */
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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 uint16_t ao_cmd_lex_i;
+__pdata uint32_t ao_cmd_lex_u32;
+__pdata char ao_cmd_lex_c;
+__pdata enum ao_cmd_status ao_cmd_status;
+
+#define CMD_LEN 48
+
+static __xdata char cmd_line[CMD_LEN];
+static __pdata uint8_t cmd_len;
+static __pdata uint8_t cmd_i;
+
+static void
+put_string(__code char *s)
+{
+ char c;
+ while ((c = *s++))
+ putchar(c);
+}
+
+static void
+readline(void)
+{
+ __pdata char c;
+ if (ao_echo())
+ put_string("> ");
+ cmd_len = 0;
+ for (;;) {
+ flush();
+ c = getchar();
+ /* backspace/delete */
+ if (c == '\010' || c == '\177') {
+ if (cmd_len != 0) {
+ if (ao_echo())
+ put_string("\010 \010");
+ --cmd_len;
+ }
+ continue;
+ }
+
+ /* ^U */
+ if (c == '\025') {
+ while (cmd_len != 0) {
+ if (ao_echo())
+ put_string("\010 \010");
+ --cmd_len;
+ }
+ continue;
+ }
+
+ /* map CR to NL */
+ if (c == '\r')
+ c = '\n';
+
+ if (c == '\n') {
+ if (ao_echo())
+ putchar('\n');
+ break;
+ }
+
+ if (cmd_len >= CMD_LEN - 2) {
+ if (ao_echo())
+ putchar('\007');
+ continue;
+ }
+ cmd_line[cmd_len++] = c;
+ if (ao_echo())
+ putchar(c);
+ }
+ cmd_line[cmd_len++] = '\n';
+ cmd_line[cmd_len++] = '\0';
+ cmd_i = 0;
+}
+
+void
+ao_cmd_lex(void)
+{
+ ao_cmd_lex_c = '\n';
+ if (cmd_i < cmd_len)
+ ao_cmd_lex_c = cmd_line[cmd_i++];
+}
+
+static void
+putnibble(uint8_t v)
+{
+ if (v < 10)
+ putchar(v + '0');
+ else
+ putchar(v + ('a' - 10));
+}
+
+void
+ao_cmd_put16(uint16_t v)
+{
+ ao_cmd_put8(v >> 8);
+ ao_cmd_put8(v);
+}
+
+void
+ao_cmd_put8(uint8_t v)
+{
+ putnibble((v >> 4) & 0xf);
+ putnibble(v & 0xf);
+}
+
+void
+ao_cmd_white(void)
+{
+ while (ao_cmd_lex_c == ' ' || ao_cmd_lex_c == '\t')
+ 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;
+ int8_t n;
+
+ ao_cmd_lex_i = 0;
+ ao_cmd_white();
+ for(;;) {
+ 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;
+ ao_cmd_lex();
+ }
+ if (r != ao_cmd_success)
+ ao_cmd_status = r;
+}
+
+void
+ao_cmd_decimal(void)
+{
+ __pdata uint8_t r = ao_cmd_lex_error;
+
+ ao_cmd_lex_u32 = 0;
+ ao_cmd_white();
+ for(;;) {
+ if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9')
+ ao_cmd_lex_u32 = (ao_cmd_lex_u32 * 10) + (ao_cmd_lex_c - '0');
+ else
+ break;
+ r = ao_cmd_success;
+ ao_cmd_lex();
+ }
+ if (r != ao_cmd_success)
+ ao_cmd_status = r;
+ ao_cmd_lex_i = (uint16_t) ao_cmd_lex_u32;
+}
+
+uint8_t
+ao_match_word(__code char *word)
+{
+ while (*word) {
+ if (ao_cmd_lex_c != *word) {
+ ao_cmd_status = ao_cmd_syntax_error;
+ return 0;
+ }
+ word++;
+ ao_cmd_lex();
+ }
+ return 1;
+}
+
+static void
+echo(void)
+{
+ ao_cmd_hex();
+ if (ao_cmd_status == ao_cmd_success)
+ ao_stdios[ao_cur_stdio].echo = ao_cmd_lex_i != 0;
+}
+
+static void
+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));
+ ao_arch_reboot();
+ ao_panic(AO_PANIC_REBOOT);
+}
+
+static void
+version(void)
+{
+ printf("manufacturer %s\n", ao_manufacturer);
+ printf("product %s\n", ao_product);
+ printf("serial-number %u\n", ao_serial_number);
+#if HAS_LOG
+ printf("log-format %u\n", ao_log_format);
+#endif
+ printf("software-version %s\n", ao_version);
+}
+
+#define NUM_CMDS 11
+
+static __code struct ao_cmds *__xdata (ao_cmds[NUM_CMDS]);
+static __pdata uint8_t ao_ncmds;
+
+static void
+help(void)
+{
+ register uint8_t cmds;
+ register uint8_t cmd;
+ register __code struct ao_cmds * cs;
+
+ for (cmds = 0; cmds < ao_ncmds; cmds++) {
+ cs = ao_cmds[cmds];
+ for (cmd = 0; cs[cmd].func; cmd++)
+ printf("%-45s %s\n",
+ cs[cmd].help,
+ cs[cmd].help+1+strlen(cs[cmd].help));
+ }
+}
+
+static void
+report(void)
+{
+ switch(ao_cmd_status) {
+ case ao_cmd_lex_error:
+ case ao_cmd_syntax_error:
+ puts("Syntax error");
+ ao_cmd_status = 0;
+ default:
+ break;
+ }
+}
+
+void
+ao_cmd_register(__code struct ao_cmds *cmds)
+{
+ if (ao_ncmds >= NUM_CMDS)
+ ao_panic(AO_PANIC_CMD);
+ ao_cmds[ao_ncmds++] = cmds;
+}
+
+void
+ao_cmd(void)
+{
+ char c;
+ uint8_t cmd, cmds;
+ __code struct ao_cmds * __xdata cs;
+ void (*__xdata func)(void);
+
+ for (;;) {
+ readline();
+ ao_cmd_lex();
+ ao_cmd_white();
+ c = ao_cmd_lex_c;
+ ao_cmd_lex();
+ if (c == '\r' || c == '\n')
+ continue;
+ func = (void (*)(void)) NULL;
+ for (cmds = 0; cmds < ao_ncmds; cmds++) {
+ cs = ao_cmds[cmds];
+ for (cmd = 0; cs[cmd].func; cmd++)
+ if (cs[cmd].help[0] == c) {
+ func = cs[cmd].func;
+ break;
+ }
+ if (func)
+ break;
+ }
+ if (func)
+ (*func)();
+ else
+ ao_cmd_status = ao_cmd_syntax_error;
+ report();
+ }
+}
+
+__xdata struct ao_task ao_cmd_task;
+
+__code struct ao_cmds ao_base_cmds[] = {
+ { help, "?\0Help" },
+ { ao_task_info, "T\0Show tasks" },
+ { echo, "E <0 off, 1 on>\0Set echo mode" },
+ { ao_reboot, "r eboot\0Reboot" },
+ { version, "v\0Version" },
+ { 0, NULL },
+};
+
+void
+ao_cmd_init(void)
+{
+ ao_cmd_register(&ao_base_cmds[0]);
+ ao_add_task(&ao_cmd_task, ao_cmd, "cmd");
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_config ao_config;
+__pdata uint8_t ao_config_loaded;
+__pdata uint8_t ao_config_dirty;
+__xdata uint8_t ao_config_mutex;
+
+#define AO_CONFIG_DEFAULT_MAIN_DEPLOY 250
+#define AO_CONFIG_DEFAULT_RADIO_CHANNEL 0
+#define AO_CONFIG_DEFAULT_CALLSIGN "N0CALL"
+#define AO_CONFIG_DEFAULT_ACCEL_ZERO_G 16000
+#define AO_CONFIG_DEFAULT_APOGEE_DELAY 0
+#define AO_CONFIG_DEFAULT_IGNITE_MODE AO_IGNITE_MODE_DUAL
+#define AO_CONFIG_DEFAULT_PAD_ORIENTATION AO_PAD_ORIENTATION_ANTENNA_UP
+#if HAS_EEPROM
+#ifndef USE_INTERNAL_FLASH
+#error Please define USE_INTERNAL_FLASH
+#endif
+#endif
+#if USE_INTERNAL_FLASH
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX ao_storage_config
+#else
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX ((uint32_t) 192 * (uint32_t) 1024)
+#endif
+
+#if HAS_EEPROM
+static void
+_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();
+}
+
+void
+ao_config_put(void)
+{
+ ao_mutex_get(&ao_config_mutex);
+ _ao_config_put();
+ ao_mutex_put(&ao_config_mutex);
+}
+#endif
+
+static void
+_ao_config_get(void)
+{
+ if (ao_config_loaded)
+ return;
+#if HAS_EEPROM
+ ao_storage_setup();
+ ao_storage_read(ao_storage_config, &ao_config, sizeof (ao_config));
+#endif
+ 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 */
+ if (ao_config.minor < 1)
+ ao_config.apogee_delay = AO_CONFIG_DEFAULT_APOGEE_DELAY;
+ /* Fixups for minor version 2 */
+ if (ao_config.minor < 2) {
+ ao_config.accel_plus_g = 0;
+ ao_config.accel_minus_g = 0;
+ }
+ /* Fixups for minor version 3 */
+ if (ao_config.minor < 3)
+ ao_config.radio_cal = ao_radio_cal;
+ /* Fixups for minor version 4 */
+ if (ao_config.minor < 4)
+ ao_config.flight_log_max = AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX;
+ /* Fixupes for minor version 5 */
+ if (ao_config.minor < 5)
+ ao_config.ignite_mode = AO_CONFIG_DEFAULT_IGNITE_MODE;
+ if (ao_config.minor < 6)
+ ao_config.pad_orientation = AO_CONFIG_DEFAULT_PAD_ORIENTATION;
+ if (ao_config.minor < 7)
+ 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;
+ }
+ ao_config_loaded = 1;
+}
+
+static void
+_ao_config_edit_start(void)
+{
+ ao_mutex_get(&ao_config_mutex);
+ _ao_config_get();
+}
+
+static void
+_ao_config_edit_finish(void)
+{
+ ao_config_dirty = 1;
+ ao_mutex_put(&ao_config_mutex);
+}
+
+void
+ao_config_get(void)
+{
+ _ao_config_edit_start();
+ ao_mutex_put(&ao_config_mutex);
+}
+
+void
+ao_config_callsign_show(void)
+{
+ printf ("Callsign: \"%s\"\n", ao_config.callsign);
+}
+
+void
+ao_config_callsign_set(void) __reentrant
+{
+ uint8_t c;
+ static __xdata char callsign[AO_MAX_CALLSIGN + 1];
+
+ memset(callsign, '\0', sizeof callsign);
+ ao_cmd_white();
+ c = 0;
+ while (ao_cmd_lex_c != '\n') {
+ if (c < AO_MAX_CALLSIGN)
+ callsign[c++] = ao_cmd_lex_c;
+ else
+ ao_cmd_status = ao_cmd_lex_error;
+ ao_cmd_lex();
+ }
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ _ao_config_edit_start();
+ memcpy(&ao_config.callsign, &callsign,
+ AO_MAX_CALLSIGN + 1);
+ _ao_config_edit_finish();
+}
+
+void
+ao_config_radio_channel_show(void) __reentrant
+{
+ printf("Radio channel: %d\n",
+ ao_config.radio_channel);
+}
+
+void
+ao_config_radio_channel_set(void) __reentrant
+{
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ _ao_config_edit_start();
+ ao_config.radio_channel = ao_cmd_lex_i;
+ _ao_config_edit_finish();
+ ao_radio_recv_abort();
+}
+
+#if HAS_ADC
+
+void
+ao_config_main_deploy_show(void) __reentrant
+{
+ printf("Main deploy: %d meters\n",
+ ao_config.main_deploy);
+}
+
+void
+ao_config_main_deploy_set(void) __reentrant
+{
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ _ao_config_edit_start();
+ ao_config.main_deploy = ao_cmd_lex_i;
+ _ao_config_edit_finish();
+}
+
+#if HAS_ACCEL
+void
+ao_config_accel_calibrate_show(void) __reentrant
+{
+ printf("Accel cal +1g: %d -1g: %d\n",
+ ao_config.accel_plus_g, ao_config.accel_minus_g);
+}
+
+#define ACCEL_CALIBRATE_SAMPLES 1024
+#define ACCEL_CALIBRATE_SHIFT 10
+
+static int16_t
+ao_config_accel_calibrate_auto(char *orientation) __reentrant
+{
+ uint16_t i;
+ int32_t accel_total;
+ uint8_t cal_adc_ring;
+
+ printf("Orient antenna %s and press a key...", orientation);
+ flush();
+ (void) getchar();
+ puts("\r\n"); flush();
+ puts("Calibrating..."); flush();
+ i = ACCEL_CALIBRATE_SAMPLES;
+ accel_total = 0;
+ cal_adc_ring = ao_sample_adc;
+ while (i) {
+ ao_sleep(DATA_TO_XDATA(&ao_sample_adc));
+ while (i && cal_adc_ring != ao_sample_adc) {
+ accel_total += (int32_t) ao_adc_ring[cal_adc_ring].accel;
+ cal_adc_ring = ao_adc_ring_next(cal_adc_ring);
+ i--;
+ }
+ }
+ return accel_total >> ACCEL_CALIBRATE_SHIFT;
+}
+
+void
+ao_config_accel_calibrate_set(void) __reentrant
+{
+ int16_t up, down;
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ if (ao_cmd_lex_i == 0) {
+ up = ao_config_accel_calibrate_auto("up");
+ down = ao_config_accel_calibrate_auto("down");
+ } else {
+ up = ao_cmd_lex_i;
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ down = ao_cmd_lex_i;
+ }
+ if (up >= down) {
+ printf("Invalid accel: up (%d) down (%d)\n",
+ up, down);
+ return;
+ }
+ _ao_config_edit_start();
+ ao_config.accel_plus_g = up;
+ ao_config.accel_minus_g = down;
+ _ao_config_edit_finish();
+}
+#endif /* HAS_ACCEL */
+
+void
+ao_config_apogee_delay_show(void) __reentrant
+{
+ printf("Apogee delay: %d seconds\n",
+ ao_config.apogee_delay);
+}
+
+void
+ao_config_apogee_delay_set(void) __reentrant
+{
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ _ao_config_edit_start();
+ ao_config.apogee_delay = ao_cmd_lex_i;
+ _ao_config_edit_finish();
+}
+
+#endif /* HAS_ADC */
+
+void
+ao_config_radio_cal_show(void) __reentrant
+{
+ printf("Radio cal: %ld\n", ao_config.radio_cal);
+}
+
+void
+ao_config_radio_cal_set(void) __reentrant
+{
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ _ao_config_edit_start();
+ ao_config.radio_setting = ao_config.radio_cal = ao_cmd_lex_u32;
+ _ao_config_edit_finish();
+}
+
+#if HAS_LOG
+void
+ao_config_log_show(void) __reentrant
+{
+ printf("Max flight log: %d kB\n", (int16_t) (ao_config.flight_log_max >> 10));
+}
+
+void
+ao_config_log_set(void) __reentrant
+{
+ uint16_t block = (uint16_t) (ao_storage_block >> 10);
+ uint16_t config = (uint16_t) (ao_storage_config >> 10);
+
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ if (ao_log_present())
+ printf("Storage must be empty before changing log size\n");
+ else if (block > 1024 && (ao_cmd_lex_i & (block - 1)))
+ printf("Flight log size must be multiple of %d kB\n", block);
+ else if (ao_cmd_lex_i > config)
+ printf("Flight log max %d kB\n", config);
+ else {
+ _ao_config_edit_start();
+ ao_config.flight_log_max = (uint32_t) ao_cmd_lex_i << 10;
+ _ao_config_edit_finish();
+ }
+}
+#endif /* HAS_LOG */
+
+#if HAS_IGNITE
+void
+ao_config_ignite_mode_show(void) __reentrant
+{
+ printf("Ignite mode: %d\n", ao_config.ignite_mode);
+}
+
+void
+ao_config_ignite_mode_set(void) __reentrant
+{
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ _ao_config_edit_start();
+ ao_config.ignite_mode = ao_cmd_lex_i;
+ _ao_config_edit_finish();
+}
+#endif
+
+#if HAS_ACCEL
+void
+ao_config_pad_orientation_show(void) __reentrant
+{
+ printf("Pad orientation: %d\n", ao_config.pad_orientation);
+}
+
+void
+ao_config_pad_orientation_set(void) __reentrant
+{
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ _ao_config_edit_start();
+ ao_cmd_lex_i &= 1;
+ if (ao_config.pad_orientation != ao_cmd_lex_i) {
+ uint16_t t;
+ t = ao_config.accel_plus_g;
+ ao_config.accel_plus_g = 0x7fff - ao_config.accel_minus_g;
+ ao_config.accel_minus_g = 0x7fff - t;
+ }
+ ao_config.pad_orientation = ao_cmd_lex_i;
+ _ao_config_edit_finish();
+}
+#endif
+
+void
+ao_config_radio_setting_show(void) __reentrant
+{
+ printf("Radio setting: %ld\n", ao_config.radio_setting);
+}
+
+void
+ao_config_radio_setting_set(void) __reentrant
+{
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ _ao_config_edit_start();
+ ao_config.radio_setting = ao_cmd_lex_u32;
+ ao_config.radio_channel = 0;
+ _ao_config_edit_finish();
+ ao_radio_recv_abort();
+}
+
+void
+ao_config_radio_enable_show(void) __reentrant
+{
+ printf("Radio enable: %d\n", ao_config.radio_enable);
+}
+
+void
+ao_config_radio_enable_set(void) __reentrant
+{
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ _ao_config_edit_start();
+ ao_config.radio_enable = ao_cmd_lex_i;
+ _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;
+ void (*show)(void) __reentrant;
+};
+
+static void
+ao_config_help(void) __reentrant;
+
+static void
+ao_config_show(void) __reentrant;
+
+static void
+ao_config_write(void) __reentrant;
+
+__code struct ao_config_var ao_config_vars[] = {
+#if HAS_ADC
+ { "m <meters>\0Main deploy (in meters)",
+ ao_config_main_deploy_set, ao_config_main_deploy_show, },
+ { "d <delay>\0Apogee delay (in seconds)",
+ ao_config_apogee_delay_set, ao_config_apogee_delay_show },
+#endif /* HAS_ADC */
+ { "r <channel>\0Radio channel (freq = 434.550 + chan * .1)",
+ ao_config_radio_channel_set, ao_config_radio_channel_show },
+ { "c <call>\0Callsign (8 char max)",
+ ao_config_callsign_set, ao_config_callsign_show },
+ { "R <setting>\0Radio freq control (freq = 434.550 * setting/cal)",
+ ao_config_radio_setting_set, ao_config_radio_setting_show },
+ { "e <0 disable, 1 enable>\0Enable telemetry and RDF",
+ ao_config_radio_enable_set, ao_config_radio_enable_show },
+#if HAS_ACCEL
+ { "a <+g> <-g>\0Accel calib (0 for auto)",
+ ao_config_accel_calibrate_set,ao_config_accel_calibrate_show },
+#endif /* HAS_ACCEL */
+ { "f <cal>\0Radio calib (cal = rf/(xtal/2^16))",
+ ao_config_radio_cal_set, ao_config_radio_cal_show },
+#if HAS_LOG
+ { "l <size>\0Flight log size in kB",
+ ao_config_log_set, ao_config_log_show },
+#endif
+#if HAS_IGNITE
+ { "i <0 dual, 1 apogee, 2 main>\0Set igniter mode",
+ ao_config_ignite_mode_set, ao_config_ignite_mode_show },
+#endif
+#if HAS_ACCEL
+ { "o <0 antenna up, 1 antenna down>\0Set pad orientation",
+ ao_config_pad_orientation_set,ao_config_pad_orientation_show },
+#endif
+#if HAS_AES
+ { "k <32 hex digits>\0Set AES encryption key",
+ ao_config_key_set, ao_config_key_show },
+#endif
+ { "s\0Show",
+ ao_config_show, 0 },
+#if HAS_EEPROM
+ { "w\0Write to eeprom",
+ ao_config_write, 0 },
+#endif
+ { "?\0Help",
+ ao_config_help, 0 },
+ { 0, 0, 0 }
+};
+
+void
+ao_config_set(void)
+{
+ char c;
+ uint8_t cmd;
+ void (*__xdata func)(void) __reentrant;
+
+ ao_cmd_white();
+ c = ao_cmd_lex_c;
+ ao_cmd_lex();
+ func = 0;
+ for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
+ if (ao_config_vars[cmd].str[0] == c) {
+ (*ao_config_vars[cmd].set)();
+ return;
+ }
+ ao_cmd_status = ao_cmd_syntax_error;
+}
+
+static void
+ao_config_help(void) __reentrant
+{
+ uint8_t cmd;
+ for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
+ printf("%-20s %s\n",
+ ao_config_vars[cmd].str,
+ ao_config_vars[cmd].str+1+strlen(ao_config_vars[cmd].str));
+}
+
+static void
+ao_config_show(void) __reentrant
+{
+ uint8_t cmd;
+ printf("Config version: %d.%d\n",
+ ao_config.major, ao_config.minor);
+ for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
+ if (ao_config_vars[cmd].show)
+ (*ao_config_vars[cmd].show)();
+}
+
+#if HAS_EEPROM
+static void
+ao_config_write(void) __reentrant
+{
+ uint8_t saved = 0;
+ ao_mutex_get(&ao_config_mutex);
+ if (ao_config_dirty) {
+ _ao_config_put();
+ ao_config_dirty = 0;
+ saved = 1;
+ }
+ ao_mutex_put(&ao_config_mutex);
+ if (saved)
+ puts("Saved");
+ else
+ puts("Nothing to save");
+}
+#endif
+
+__code struct ao_cmds ao_config_cmds[] = {
+ { ao_config_set, "c <var> <value>\0Set config variable (? for help, s to show)" },
+ { 0, NULL },
+};
+
+void
+ao_config_init(void)
+{
+ ao_cmd_register(&ao_config_cmds[0]);
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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.
+ */
+
+#if !defined(AO_CONVERT_TEST) && !defined(AO_FLIGHT_TEST)
+#include "ao.h"
+#endif
+
+static const int16_t altitude_table[] = {
+#include "altitude.h"
+};
+
+#define ALT_FRAC_SCALE (1 << ALT_FRAC_BITS)
+#define ALT_FRAC_MASK (ALT_FRAC_SCALE - 1)
+
+int16_t
+ao_pres_to_altitude(int16_t pres) __reentrant
+{
+ uint8_t o;
+ int16_t part;
+
+ if (pres < 0)
+ pres = 0;
+ o = pres >> ALT_FRAC_BITS;
+ part = pres & ALT_FRAC_MASK;
+
+ return ((int32_t) altitude_table[o] * (ALT_FRAC_SCALE - part) +
+ (int32_t) altitude_table[o+1] * part + (ALT_FRAC_SCALE >> 1)) >> ALT_FRAC_BITS;
+}
+
+int16_t
+ao_altitude_to_pres(int16_t alt) __reentrant
+{
+ int16_t span, sub_span;
+ uint8_t l, h, m;
+ int32_t pres;
+
+ l = 0;
+ h = NALT - 1;
+ while ((h - l) != 1) {
+ m = (l + h) >> 1;
+ if (altitude_table[m] < alt)
+ h = m;
+ else
+ l = m;
+ }
+ span = altitude_table[l] - altitude_table[h];
+ sub_span = altitude_table[l] - alt;
+ pres = ((((int32_t) l * (span - sub_span) + (int32_t) h * sub_span) << ALT_FRAC_BITS) + (span >> 1)) / span;
+ if (pres > 32767)
+ pres = 32767;
+ if (pres < 0)
+ pres = 0;
+ return (int16_t) pres;
+}
+
+int16_t
+ao_temp_to_dC(int16_t temp) __reentrant
+{
+ int16_t ret;
+
+ /* Output voltage at 0°C = 0.755V
+ * Coefficient = 0.00247V/°C
+ * Reference voltage = 1.25V
+ *
+ * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247
+ * = (value - 19791.268) / 32768 * 1.25 / 0.00247
+ * ≃ (value - 19791) * 1012 / 65536
+ */
+ ret = ((temp - 19791) * 1012L) >> 16;
+ return ret;
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+#define AO_CONVERT_TEST
+#include "ao_host.h"
+#include "ao_convert.c"
+
+#define STEP 1
+
+static inline i_abs(int i) { return i < 0 ? -i : i; }
+
+main ()
+{
+ int i;
+ int16_t p_to_a, p_to_a_to_p;
+ int16_t a_to_p, a_to_p_to_a;
+ int max_p_error = 0, max_p_error_p = -1;
+ int max_a_error = 0, max_a_error_a = -1;
+ int p_error;
+ int a_error;
+ int ret = 0;
+
+ for (i = 0; i < 32767 + STEP; i += STEP) {
+ if (i > 32767)
+ i = 32767;
+ p_to_a = ao_pres_to_altitude(i);
+ p_to_a_to_p = ao_altitude_to_pres(p_to_a);
+ p_error = i_abs(p_to_a_to_p - i);
+ if (p_error > max_p_error) {
+ max_p_error = p_error;
+ max_p_error_p = i;
+ }
+// printf ("pres %d alt %d pres %d\n",
+// i, p_to_a, p_to_a_to_p);
+ }
+ for (i = -1578; i < 15835 + STEP; i += STEP) {
+ if (i > 15835)
+ i = 15835;
+ a_to_p = ao_altitude_to_pres(i);
+ a_to_p_to_a = ao_pres_to_altitude(a_to_p);
+ a_error = i_abs(a_to_p_to_a - i);
+ if (a_error > max_a_error) {
+ max_a_error = a_error;
+ max_a_error_a = i;
+ }
+// printf ("alt %d pres %d alt %d\n",
+// i, a_to_p, a_to_p_to_a);
+ }
+ if (max_p_error > 2) {
+ printf ("max p error %d at %d\n", max_p_error,
+ max_p_error_p);
+ ret++;
+ }
+ if (max_a_error > 1) {
+ printf ("max a error %d at %d\n", max_a_error,
+ max_a_error_a);
+ ret++;
+ }
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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"
+
+/*
+ * For hardware without eeprom, the config code still
+ * wants to call these functions
+ */
+uint8_t
+ao_ee_write_config(uint8_t *buf, uint16_t len) __reentrant
+{
+ (void) buf;
+ (void) len;
+ return 1;
+}
+
+uint8_t
+ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant
+{
+ memset(buf, '\0', len);
+ return 1;
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_FLIGHT_TEST
+#include "ao.h"
+#endif
+
+#ifndef HAS_ACCEL
+#error Please define HAS_ACCEL
+#endif
+
+#ifndef HAS_GPS
+#error Please define HAS_GPS
+#endif
+
+#ifndef HAS_USB
+#error Please define HAS_USB
+#endif
+
+/* Main flight thread. */
+
+__pdata enum ao_flight_state ao_flight_state; /* current flight state */
+__pdata uint16_t ao_boost_tick; /* time of launch detect */
+
+/*
+ * track min/max data over a long interval to detect
+ * resting
+ */
+__pdata uint16_t ao_interval_end;
+__pdata int16_t ao_interval_min_height;
+__pdata int16_t ao_interval_max_height;
+__pdata uint8_t ao_flight_force_idle;
+
+/* We also have a clock, which can be used to sanity check things in
+ * case of other failures
+ */
+
+#define BOOST_TICKS_MAX AO_SEC_TO_TICKS(15)
+
+/* Landing is detected by getting constant readings from both pressure and accelerometer
+ * for a fairly long time (AO_INTERVAL_TICKS)
+ */
+#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(10)
+
+#define abs(a) ((a) < 0 ? -(a) : (a))
+
+void
+ao_flight(void)
+{
+ ao_sample_init();
+ ao_flight_state = ao_flight_startup;
+ for (;;) {
+
+ /*
+ * Process ADC samples, just looping
+ * until the sensors are calibrated.
+ */
+ if (!ao_sample())
+ continue;
+
+ switch (ao_flight_state) {
+ case ao_flight_startup:
+
+ /* Check to see what mode we should go to.
+ * - Invalid mode if accel cal appears to be out
+ * - pad mode if we're upright,
+ * - idle mode otherwise
+ */
+#if HAS_ACCEL
+ if (ao_config.accel_plus_g == 0 ||
+ ao_config.accel_minus_g == 0 ||
+ ao_ground_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP ||
+ ao_ground_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP)
+ {
+ /* Detected an accel value outside -1.5g to 1.5g
+ * (or uncalibrated values), so we go into invalid mode
+ */
+ ao_flight_state = ao_flight_invalid;
+
+ /* Turn on packet system in invalid mode on TeleMetrum */
+ ao_packet_slave_start();
+ } else
+#endif
+ if (!ao_flight_force_idle
+#if HAS_ACCEL
+ && ao_ground_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP
+#endif
+ )
+ {
+ /* Set pad mode - we can fly! */
+ ao_flight_state = ao_flight_pad;
+#if HAS_USB
+ /* Disable the USB controller in flight mode
+ * to save power
+ */
+ ao_usb_disable();
+#endif
+
+#if !HAS_ACCEL
+ /* Disable packet mode in pad state on TeleMini */
+ ao_packet_slave_stop();
+#endif
+
+ /* Turn on telemetry system */
+ ao_rdf_set(1);
+ ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD);
+
+ /* signal successful initialization by turning off the LED */
+ ao_led_off(AO_LED_RED);
+ } else {
+ /* Set idle mode */
+ ao_flight_state = ao_flight_idle;
+
+#if HAS_ACCEL
+ /* Turn on packet system in idle mode on TeleMetrum */
+ ao_packet_slave_start();
+#endif
+
+ /* signal successful initialization by turning off the LED */
+ ao_led_off(AO_LED_RED);
+ }
+ /* wakeup threads due to state change */
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+
+ break;
+ case ao_flight_pad:
+
+ /* pad to boost:
+ *
+ * barometer: > 20m vertical motion
+ * OR
+ * accelerometer: > 2g AND velocity > 5m/s
+ *
+ * The accelerometer should always detect motion before
+ * the barometer, but we use both to make sure this
+ * transition is detected. If the device
+ * doesn't have an accelerometer, then ignore the
+ * speed and acceleration as they are quite noisy
+ * on the pad.
+ */
+ if (ao_height > AO_M_TO_HEIGHT(20)
+#if HAS_ACCEL
+ || (ao_accel > AO_MSS_TO_ACCEL(20) &&
+ ao_speed > AO_MS_TO_SPEED(5))
+#endif
+ )
+ {
+ ao_flight_state = ao_flight_boost;
+ ao_boost_tick = ao_sample_tick;
+
+ /* start logging data */
+ ao_log_start();
+
+ /* Increase telemetry rate */
+ ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_FLIGHT);
+
+ /* disable RDF beacon */
+ ao_rdf_set(0);
+
+#if HAS_GPS
+ /* Record current GPS position by waking up GPS log tasks */
+ ao_wakeup(&ao_gps_data);
+ ao_wakeup(&ao_gps_tracking_data);
+#endif
+
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+ }
+ break;
+ case ao_flight_boost:
+
+ /* boost to fast:
+ *
+ * accelerometer: start to fall at > 1/4 G
+ * OR
+ * time: boost for more than 15 seconds
+ *
+ * Detects motor burn out by the switch from acceleration to
+ * deceleration, or by waiting until the maximum burn duration
+ * (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_boost_tick) > BOOST_TICKS_MAX)
+ {
+#if HAS_ACCEL
+ ao_flight_state = ao_flight_fast;
+#else
+ ao_flight_state = ao_flight_coast;
+#endif
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+ }
+ break;
+#if HAS_ACCEL
+ case ao_flight_fast:
+ /*
+ * This is essentially the same as coast,
+ * but the barometer is being ignored as
+ * it may be unreliable.
+ */
+ if (ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED))
+ {
+ 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:
+
+ /* apogee detect: coast to drogue deploy:
+ *
+ * speed: < 0
+ *
+ * Also make sure the model altitude is tracking
+ * the measured altitude reasonably closely; otherwise
+ * we're probably transsonic.
+ */
+ if (ao_speed < 0
+#if !HAS_ACCEL
+ && (ao_sample_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 100)
+#endif
+ )
+ {
+ /* ignite the drogue charge */
+ ao_ignite(ao_igniter_drogue);
+
+ /* slow down the telemetry system */
+ ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER);
+
+ /* Turn the RDF beacon back on */
+ ao_rdf_set(1);
+
+ /* and enter drogue state */
+ 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:
+
+ /* drogue to main deploy:
+ *
+ * barometer: reach main deploy altitude
+ *
+ * Would like to use the accelerometer for this test, but
+ * the orientation of the flight computer is unknown after
+ * drogue deploy, so we ignore it. Could also detect
+ * high descent rate using the pressure sensor to
+ * recognize drogue deploy failure and eject the main
+ * at that point. Perhaps also use the drogue sense lines
+ * to notice continutity?
+ */
+ if (ao_height <= ao_config.main_deploy)
+ {
+ ao_ignite(ao_igniter_main);
+
+ /*
+ * Start recording min/max height
+ * to figure out when the rocket has landed
+ */
+
+ /* initialize interval values */
+ ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
+
+ ao_interval_min_height = ao_interval_max_height = ao_avg_height;
+
+ ao_flight_state = ao_flight_main;
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+ }
+ break;
+
+ /* fall through... */
+ case ao_flight_main:
+
+ /* main to land:
+ *
+ * barometer: altitude stable
+ */
+
+ if (ao_avg_height < ao_interval_min_height)
+ ao_interval_min_height = ao_avg_height;
+ if (ao_avg_height > ao_interval_max_height)
+ ao_interval_max_height = ao_avg_height;
+
+ if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) {
+ if (ao_interval_max_height - ao_interval_min_height <= AO_M_TO_HEIGHT(4))
+ {
+ ao_flight_state = ao_flight_landed;
+
+ /* turn off the ADC capture */
+ ao_timer_set_adc_interval(0);
+
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+ }
+ ao_interval_min_height = ao_interval_max_height = ao_avg_height;
+ ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
+ }
+ break;
+ case ao_flight_landed:
+ break;
+ }
+ }
+}
+
+static __xdata struct ao_task flight_task;
+
+void
+ao_flight_init(void)
+{
+ ao_flight_state = ao_flight_startup;
+ ao_add_task(&flight_task, ao_flight, "flight");
+}
--- /dev/null
+/*
+ * 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"
+
+/* Main flight thread. */
+
+__pdata enum ao_flight_state ao_flight_state; /* current flight state */
+__pdata uint16_t ao_launch_tick; /* time of launch detect */
+
+/*
+ * track min/max data over a long interval to detect
+ * resting
+ */
+__pdata uint16_t ao_interval_end;
+__pdata int16_t ao_interval_min_height;
+__pdata int16_t ao_interval_max_height;
+
+__pdata uint8_t ao_flight_force_idle;
+
+/* Landing is detected by getting constant readings from both pressure and accelerometer
+ * for a fairly long time (AO_INTERVAL_TICKS)
+ */
+#define AO_INTERVAL_TICKS AO_SEC_TO_TICKS(5)
+
+static void
+ao_flight_nano(void)
+{
+ ao_sample_init();
+ ao_flight_state = ao_flight_startup;
+
+ for (;;) {
+ /*
+ * Process ADC samples, just looping
+ * until the sensors are calibrated.
+ */
+ if (!ao_sample())
+ continue;
+
+ switch (ao_flight_state) {
+ case ao_flight_startup:
+ if (ao_flight_force_idle) {
+ /* Set idle mode */
+ ao_flight_state = ao_flight_idle;
+ } else {
+ ao_flight_state = ao_flight_pad;
+ /* Disable packet mode in pad state */
+ ao_packet_slave_stop();
+
+ /* Turn on telemetry system */
+ ao_rdf_set(1);
+ ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD);
+ }
+ /* signal successful initialization by turning off the LED */
+ ao_led_off(AO_LED_RED);
+
+ /* wakeup threads due to state change */
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+ break;
+ case ao_flight_pad:
+ if (ao_height> AO_M_TO_HEIGHT(20)) {
+ ao_flight_state = ao_flight_drogue;
+ ao_launch_tick = ao_sample_tick;
+
+ /* start logging data */
+ ao_log_start();
+
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+ }
+ break;
+ case ao_flight_drogue:
+ /* drogue/main to land:
+ *
+ * barometer: altitude stable
+ */
+
+ if (ao_height < ao_interval_min_height)
+ ao_interval_min_height = ao_height;
+ if (ao_height > ao_interval_max_height)
+ ao_interval_max_height = ao_height;
+
+ if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) {
+ if (ao_interval_max_height - ao_interval_min_height < AO_M_TO_HEIGHT(5))
+ {
+ ao_flight_state = ao_flight_landed;
+
+ /* turn off the ADC capture */
+ ao_timer_set_adc_interval(0);
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+ }
+ ao_interval_min_height = ao_interval_max_height = ao_height;
+ ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
+ }
+ break;
+ }
+ }
+}
+
+static __xdata struct ao_task flight_task;
+
+void
+ao_flight_nano_init(void)
+{
+ ao_flight_state = ao_flight_startup;
+ ao_add_task(&flight_task, ao_flight_nano, "flight");
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_GPS_TEST
+#include "ao.h"
+#endif
+#include "ao_telem.h"
+
+void
+ao_gps_print(__xdata struct ao_gps_orig *gps_data) __reentrant
+{
+ char state;
+
+ if (gps_data->flags & AO_GPS_VALID)
+ state = AO_TELEM_GPS_STATE_LOCKED;
+ else if (gps_data->flags & AO_GPS_RUNNING)
+ state = AO_TELEM_GPS_STATE_UNLOCKED;
+ else
+ state = AO_TELEM_GPS_STATE_ERROR;
+ printf(AO_TELEM_GPS_STATE " %c "
+ AO_TELEM_GPS_NUM_SAT " %d ",
+ state,
+ (gps_data->flags & AO_GPS_NUM_SAT_MASK) >> AO_GPS_NUM_SAT_SHIFT);
+ if (!(gps_data->flags & AO_GPS_VALID))
+ return;
+ printf(AO_TELEM_GPS_LATITUDE " %ld "
+ AO_TELEM_GPS_LONGITUDE " %ld "
+ AO_TELEM_GPS_ALTITUDE " %d ",
+ gps_data->latitude,
+ gps_data->longitude,
+ gps_data->altitude);
+
+ if (gps_data->flags & AO_GPS_DATE_VALID)
+ printf(AO_TELEM_GPS_YEAR " %d "
+ AO_TELEM_GPS_MONTH " %d "
+ AO_TELEM_GPS_DAY " %d ",
+ gps_data->year,
+ gps_data->month,
+ gps_data->day);
+
+ printf(AO_TELEM_GPS_HOUR " %d "
+ AO_TELEM_GPS_MINUTE " %d "
+ AO_TELEM_GPS_SECOND " %d ",
+ gps_data->hour,
+ gps_data->minute,
+ gps_data->second);
+
+ printf(AO_TELEM_GPS_HDOP " %d ",
+ gps_data->hdop * 2);
+
+ if (gps_data->flags & AO_GPS_COURSE_VALID) {
+ printf(AO_TELEM_GPS_HERROR " %d "
+ AO_TELEM_GPS_VERROR " %d "
+ AO_TELEM_GPS_VERTICAL_SPEED " %d "
+ AO_TELEM_GPS_HORIZONTAL_SPEED " %d "
+ AO_TELEM_GPS_COURSE " %d ",
+ gps_data->h_error,
+ gps_data->v_error,
+ gps_data->climb_rate,
+ gps_data->ground_speed,
+ (int) gps_data->course * 2);
+ }
+}
+
+void
+ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data) __reentrant
+{
+ uint8_t c, n, v;
+ __xdata struct ao_gps_sat_orig *sat;
+
+ n = gps_tracking_data->channels;
+ if (n == 0)
+ return;
+
+ sat = gps_tracking_data->sats;
+ v = 0;
+ for (c = 0; c < n; c++) {
+ if (sat->svid)
+ v++;
+ sat++;
+ }
+
+ printf (AO_TELEM_SAT_NUM " %d ",
+ v);
+
+ sat = gps_tracking_data->sats;
+ v = 0;
+ for (c = 0; c < n; c++) {
+ if (sat->svid) {
+ printf (AO_TELEM_SAT_SVID "%d %d "
+ AO_TELEM_SAT_C_N_0 "%d %d ",
+ v, sat->svid,
+ v, sat->c_n_1);
+ v++;
+ }
+ sat++;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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
+ao_gps_report(void)
+{
+ static __xdata struct ao_log_record gps_log;
+ static __xdata struct ao_telemetry_location gps_data;
+ uint8_t date_reported = 0;
+
+ for (;;) {
+ ao_sleep(&ao_gps_data);
+ ao_mutex_get(&ao_gps_mutex);
+ memcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data));
+ ao_mutex_put(&ao_gps_mutex);
+
+ if (!(gps_data.flags & AO_GPS_VALID))
+ continue;
+
+ gps_log.tick = ao_gps_tick;
+ gps_log.type = AO_LOG_GPS_TIME;
+ gps_log.u.gps_time.hour = gps_data.hour;
+ gps_log.u.gps_time.minute = gps_data.minute;
+ gps_log.u.gps_time.second = gps_data.second;
+ gps_log.u.gps_time.flags = gps_data.flags;
+ ao_log_data(&gps_log);
+ gps_log.type = AO_LOG_GPS_LAT;
+ gps_log.u.gps_latitude = gps_data.latitude;
+ ao_log_data(&gps_log);
+ gps_log.type = AO_LOG_GPS_LON;
+ gps_log.u.gps_longitude = gps_data.longitude;
+ ao_log_data(&gps_log);
+ gps_log.type = AO_LOG_GPS_ALT;
+ gps_log.u.gps_altitude.altitude = gps_data.altitude;
+ gps_log.u.gps_altitude.unused = 0xffff;
+ ao_log_data(&gps_log);
+ if (!date_reported && (gps_data.flags & AO_GPS_DATE_VALID)) {
+ gps_log.type = AO_LOG_GPS_DATE;
+ gps_log.u.gps_date.year = gps_data.year;
+ gps_log.u.gps_date.month = gps_data.month;
+ gps_log.u.gps_date.day = gps_data.day;
+ gps_log.u.gps_date.extra = 0;
+ date_reported = ao_log_data(&gps_log);
+ }
+ }
+}
+
+void
+ao_gps_tracking_report(void)
+{
+ static __xdata struct ao_log_record gps_log;
+ static __xdata struct ao_telemetry_satellite gps_tracking_data;
+ uint8_t c, n;
+
+ for (;;) {
+ ao_sleep(&ao_gps_tracking_data);
+ ao_mutex_get(&ao_gps_mutex);
+ gps_log.tick = ao_gps_tick;
+ memcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data));
+ ao_mutex_put(&ao_gps_mutex);
+
+ if (!(n = gps_tracking_data.channels))
+ continue;
+
+ gps_log.type = AO_LOG_GPS_SAT;
+ for (c = 0; c < n; c++)
+ if ((gps_log.u.gps_sat.svid = gps_tracking_data.sats[c].svid))
+ {
+ gps_log.u.gps_sat.c_n = gps_tracking_data.sats[c].c_n_1;
+ ao_log_data(&gps_log);
+ }
+ }
+}
+
+__xdata struct ao_task ao_gps_report_task;
+__xdata struct ao_task ao_gps_tracking_report_task;
+
+void
+ao_gps_report_init(void)
+{
+ ao_add_task(&ao_gps_report_task, ao_gps_report, "gps_report");
+ ao_add_task(&ao_gps_tracking_report_task, ao_gps_tracking_report, "gps_tracking_report");
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#define _GNU_SOURCE
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define AO_ADC_RING 64
+#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1))
+#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1))
+
+/*
+ * One set of samples read from the A/D converter
+ */
+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 __pdata
+#define __data
+#define __xdata
+#define __code
+#define __reentrant
+
+enum ao_flight_state {
+ ao_flight_startup = 0,
+ ao_flight_idle = 1,
+ ao_flight_pad = 2,
+ ao_flight_boost = 3,
+ ao_flight_fast = 4,
+ ao_flight_coast = 5,
+ ao_flight_drogue = 6,
+ ao_flight_main = 7,
+ ao_flight_landed = 8,
+ ao_flight_invalid = 9
+};
+
+struct ao_adc ao_adc_ring[AO_ADC_RING];
+uint8_t ao_adc_head;
+
+#define ao_led_on(l)
+#define ao_led_off(l)
+#define ao_timer_set_adc_interval(i)
+#define ao_wakeup(wchan) ao_dump_state(wchan)
+#define ao_cmd_register(c)
+#define ao_usb_disable()
+#define ao_telemetry_set_interval(x)
+#define ao_delay(x)
+
+enum ao_igniter {
+ ao_igniter_drogue = 0,
+ ao_igniter_main = 1
+};
+
+void
+ao_ignite(enum ao_igniter igniter)
+{
+ printf ("ignite %s\n", igniter == ao_igniter_drogue ? "drogue" : "main");
+}
+
+struct ao_task {
+ int dummy;
+};
+
+#define ao_add_task(t,f,n)
+
+#define ao_log_start()
+#define ao_log_stop()
+
+#define AO_MS_TO_TICKS(ms) ((ms) / 10)
+#define AO_SEC_TO_TICKS(s) ((s) * 100)
+
+#define AO_FLIGHT_TEST
+
+struct ao_adc ao_adc_static;
+
+FILE *emulator_in;
+
+void
+ao_dump_state(void *wchan);
+
+void
+ao_sleep(void *wchan);
+
+const char const * const ao_state_names[] = {
+ "startup", "idle", "pad", "boost", "fast",
+ "coast", "drogue", "main", "landed", "invalid"
+};
+
+struct ao_cmds {
+ void (*func)(void);
+ const char *help;
+};
+
+
+struct ao_config {
+ uint16_t main_deploy;
+ int16_t accel_zero_g;
+};
+
+#define ao_config_get()
+
+struct ao_config ao_config = { 250, 16000 };
--- /dev/null
+/*
+ * 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_FLIGHT_TEST
+#include "ao.h"
+#endif
+
+#include "ao_kalman.h"
+
+static __pdata int32_t ao_k_height;
+static __pdata int32_t ao_k_speed;
+static __pdata int32_t ao_k_accel;
+
+#define AO_K_STEP_100 to_fix16(0.01)
+#define AO_K_STEP_2_2_100 to_fix16(0.00005)
+
+#define AO_K_STEP_10 to_fix16(0.1)
+#define AO_K_STEP_2_2_10 to_fix16(0.005)
+
+#define AO_K_STEP_1 to_fix16(1)
+#define AO_K_STEP_2_2_1 to_fix16(0.5)
+
+__pdata int16_t ao_height;
+__pdata int16_t ao_speed;
+__pdata int16_t ao_accel;
+__pdata int16_t ao_max_height;
+static __pdata int32_t ao_avg_height_scaled;
+__pdata int16_t ao_avg_height;
+
+__pdata int16_t ao_error_h;
+__pdata int16_t ao_error_h_sq_avg;
+
+#if HAS_ACCEL
+__pdata int16_t ao_error_a;
+#endif
+
+static void
+ao_kalman_predict(void)
+{
+#ifdef AO_FLIGHT_TEST
+ if (ao_sample_tick - ao_sample_prev_tick > 50) {
+ ao_k_height += ((int32_t) ao_speed * AO_K_STEP_1 +
+ (int32_t) ao_accel * AO_K_STEP_2_2_1) >> 4;
+ ao_k_speed += (int32_t) ao_accel * AO_K_STEP_1;
+
+ return;
+ }
+ if (ao_sample_tick - ao_sample_prev_tick > 5) {
+ ao_k_height += ((int32_t) ao_speed * AO_K_STEP_10 +
+ (int32_t) ao_accel * AO_K_STEP_2_2_10) >> 4;
+ ao_k_speed += (int32_t) ao_accel * AO_K_STEP_10;
+
+ return;
+ }
+ if (ao_flight_debug) {
+ printf ("predict speed %g + (%g * %g) = %g\n",
+ ao_k_speed / (65536.0 * 16.0), ao_accel / 16.0, AO_K_STEP_100 / 65536.0,
+ (ao_k_speed + (int32_t) ao_accel * AO_K_STEP_100) / (65536.0 * 16.0));
+ }
+#endif
+ ao_k_height += ((int32_t) ao_speed * AO_K_STEP_100 +
+ (int32_t) ao_accel * AO_K_STEP_2_2_100) >> 4;
+ ao_k_speed += (int32_t) ao_accel * AO_K_STEP_100;
+}
+
+static void
+ao_kalman_err_height(void)
+{
+ int16_t e;
+ int16_t height_distrust;
+#if HAS_ACCEL
+ int16_t speed_distrust;
+#endif
+
+ ao_error_h = ao_sample_height - (int16_t) (ao_k_height >> 16);
+
+ e = ao_error_h;
+ if (e < 0)
+ e = -e;
+ if (e > 127)
+ e = 127;
+#if HAS_ACCEL
+ ao_error_h_sq_avg -= ao_error_h_sq_avg >> 2;
+ ao_error_h_sq_avg += (e * e) >> 2;
+#else
+ ao_error_h_sq_avg -= ao_error_h_sq_avg >> 4;
+ ao_error_h_sq_avg += (e * e) >> 4;
+#endif
+
+ if (ao_flight_state >= ao_flight_drogue)
+ return;
+ height_distrust = ao_sample_alt - AO_MAX_BARO_HEIGHT;
+#if HAS_ACCEL
+ /* speed is stored * 16, but we need to ramp between 200 and 328, so
+ * we want to multiply by 2. The result is a shift by 3.
+ */
+ speed_distrust = (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) >> (4 - 1);
+ if (speed_distrust <= 0)
+ speed_distrust = 0;
+ else if (speed_distrust > height_distrust)
+ height_distrust = speed_distrust;
+#endif
+ if (height_distrust > 0) {
+#ifdef AO_FLIGHT_TEST
+ int old_ao_error_h = ao_error_h;
+#endif
+ if (height_distrust > 0x100)
+ height_distrust = 0x100;
+ ao_error_h = (int16_t) (((int32_t) ao_error_h * (0x100 - height_distrust)) >> 8);
+#ifdef AO_FLIGHT_TEST
+ if (ao_flight_debug) {
+ printf("over height %g over speed %g distrust: %g height: error %d -> %d\n",
+ (double) (ao_sample_alt - AO_MAX_BARO_HEIGHT),
+ (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) / 16.0,
+ height_distrust / 256.0,
+ old_ao_error_h, ao_error_h);
+ }
+#endif
+ }
+}
+
+static void
+ao_kalman_correct_baro(void)
+{
+ ao_kalman_err_height();
+#ifdef AO_FLIGHT_TEST
+ if (ao_sample_tick - ao_sample_prev_tick > 50) {
+ ao_k_height += (int32_t) AO_BARO_K0_1 * ao_error_h;
+ ao_k_speed += (int32_t) AO_BARO_K1_1 * ao_error_h;
+ ao_k_accel += (int32_t) AO_BARO_K2_1 * ao_error_h;
+ return;
+ }
+ if (ao_sample_tick - ao_sample_prev_tick > 5) {
+ ao_k_height += (int32_t) AO_BARO_K0_10 * ao_error_h;
+ ao_k_speed += (int32_t) AO_BARO_K1_10 * ao_error_h;
+ ao_k_accel += (int32_t) AO_BARO_K2_10 * ao_error_h;
+ return;
+ }
+#endif
+ ao_k_height += (int32_t) AO_BARO_K0_100 * ao_error_h;
+ ao_k_speed += (int32_t) AO_BARO_K1_100 * ao_error_h;
+ ao_k_accel += (int32_t) AO_BARO_K2_100 * ao_error_h;
+}
+
+#if HAS_ACCEL
+
+static void
+ao_kalman_err_accel(void)
+{
+ int32_t accel;
+
+ accel = (ao_ground_accel - ao_sample_accel) * ao_accel_scale;
+
+ /* Can't use ao_accel here as it is the pre-prediction value still */
+ ao_error_a = (accel - ao_k_accel) >> 16;
+}
+
+static void
+ao_kalman_correct_both(void)
+{
+ ao_kalman_err_height();
+ ao_kalman_err_accel();
+
+#ifdef AO_FLIGHT_TEST
+ if (ao_sample_tick - ao_sample_prev_tick > 50) {
+ if (ao_flight_debug) {
+ printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
+ ao_k_speed / (65536.0 * 16.0),
+ (double) ao_error_h, AO_BOTH_K10_1 / 65536.0,
+ (double) ao_error_a, AO_BOTH_K11_1 / 65536.0,
+ (ao_k_speed +
+ (int32_t) AO_BOTH_K10_1 * ao_error_h +
+ (int32_t) AO_BOTH_K11_1 * ao_error_a) / (65536.0 * 16.0));
+ }
+ ao_k_height +=
+ (int32_t) AO_BOTH_K00_1 * ao_error_h +
+ (int32_t) AO_BOTH_K01_1 * ao_error_a;
+ ao_k_speed +=
+ (int32_t) AO_BOTH_K10_1 * ao_error_h +
+ (int32_t) AO_BOTH_K11_1 * ao_error_a;
+ ao_k_accel +=
+ (int32_t) AO_BOTH_K20_1 * ao_error_h +
+ (int32_t) AO_BOTH_K21_1 * ao_error_a;
+ return;
+ }
+ if (ao_sample_tick - ao_sample_prev_tick > 5) {
+ if (ao_flight_debug) {
+ printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
+ ao_k_speed / (65536.0 * 16.0),
+ (double) ao_error_h, AO_BOTH_K10_10 / 65536.0,
+ (double) ao_error_a, AO_BOTH_K11_10 / 65536.0,
+ (ao_k_speed +
+ (int32_t) AO_BOTH_K10_10 * ao_error_h +
+ (int32_t) AO_BOTH_K11_10 * ao_error_a) / (65536.0 * 16.0));
+ }
+ ao_k_height +=
+ (int32_t) AO_BOTH_K00_10 * ao_error_h +
+ (int32_t) AO_BOTH_K01_10 * ao_error_a;
+ ao_k_speed +=
+ (int32_t) AO_BOTH_K10_10 * ao_error_h +
+ (int32_t) AO_BOTH_K11_10 * ao_error_a;
+ ao_k_accel +=
+ (int32_t) AO_BOTH_K20_10 * ao_error_h +
+ (int32_t) AO_BOTH_K21_10 * ao_error_a;
+ return;
+ }
+ if (ao_flight_debug) {
+ printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
+ ao_k_speed / (65536.0 * 16.0),
+ (double) ao_error_h, AO_BOTH_K10_100 / 65536.0,
+ (double) ao_error_a, AO_BOTH_K11_100 / 65536.0,
+ (ao_k_speed +
+ (int32_t) AO_BOTH_K10_100 * ao_error_h +
+ (int32_t) AO_BOTH_K11_100 * ao_error_a) / (65536.0 * 16.0));
+ }
+#endif
+ ao_k_height +=
+ (int32_t) AO_BOTH_K00_100 * ao_error_h +
+ (int32_t) AO_BOTH_K01_100 * ao_error_a;
+ ao_k_speed +=
+ (int32_t) AO_BOTH_K10_100 * ao_error_h +
+ (int32_t) AO_BOTH_K11_100 * ao_error_a;
+ ao_k_accel +=
+ (int32_t) AO_BOTH_K20_100 * ao_error_h +
+ (int32_t) AO_BOTH_K21_100 * ao_error_a;
+}
+
+#ifdef FORCE_ACCEL
+static void
+ao_kalman_correct_accel(void)
+{
+ ao_kalman_err_accel();
+
+ if (ao_sample_tick - ao_sample_prev_tick > 5) {
+ ao_k_height +=(int32_t) AO_ACCEL_K0_10 * ao_error_a;
+ ao_k_speed += (int32_t) AO_ACCEL_K1_10 * ao_error_a;
+ ao_k_accel += (int32_t) AO_ACCEL_K2_10 * ao_error_a;
+ return;
+ }
+ ao_k_height += (int32_t) AO_ACCEL_K0_100 * ao_error_a;
+ ao_k_speed += (int32_t) AO_ACCEL_K1_100 * ao_error_a;
+ ao_k_accel += (int32_t) AO_ACCEL_K2_100 * ao_error_a;
+}
+#endif
+#endif /* HAS_ACCEL */
+
+void
+ao_kalman(void)
+{
+ ao_kalman_predict();
+#if HAS_ACCEL
+ if (ao_flight_state <= ao_flight_coast) {
+#ifdef FORCE_ACCEL
+ ao_kalman_correct_accel();
+#else
+ ao_kalman_correct_both();
+#endif
+ } else
+#endif
+ ao_kalman_correct_baro();
+ ao_height = from_fix(ao_k_height);
+ ao_speed = from_fix(ao_k_speed);
+ ao_accel = from_fix(ao_k_accel);
+ if (ao_height > ao_max_height)
+ ao_max_height = ao_height;
+ ao_avg_height_scaled = ao_avg_height_scaled - ao_avg_height + ao_sample_height;
+#ifdef AO_FLIGHT_TEST
+ if (ao_sample_tick - ao_sample_prev_tick > 50)
+ ao_avg_height = (ao_avg_height_scaled + 1) >> 1;
+ else if (ao_sample_tick - ao_sample_prev_tick > 5)
+ ao_avg_height = (ao_avg_height_scaled + 7) >> 4;
+ else
+#endif
+ ao_avg_height = (ao_avg_height_scaled + 63) >> 7;
+#ifdef AO_FLIGHT_TEST
+ ao_sample_prev_tick = ao_sample_tick;
+#endif
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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 uint32_t ao_log_current_pos;
+__pdata uint32_t ao_log_end_pos;
+__pdata uint32_t ao_log_start_pos;
+__xdata uint8_t ao_log_running;
+__pdata enum flight_state ao_log_state;
+__xdata uint16_t ao_flight_number;
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT_FULL;
+
+void
+ao_log_flush(void)
+{
+ ao_storage_flush();
+}
+
+/*
+ * When erasing a flight log, make sure the config block
+ * has an up-to-date version of the current flight number
+ */
+
+struct ao_log_erase {
+ uint8_t unused;
+ uint16_t flight;
+};
+
+static __xdata struct ao_log_erase erase;
+
+#define LOG_MAX_ERASE 16
+
+static uint32_t
+ao_log_erase_pos(uint8_t i)
+{
+ return i * sizeof (struct ao_log_erase) + AO_STORAGE_ERASE_LOG;
+}
+
+void
+ao_log_write_erase(uint8_t pos)
+{
+ erase.unused = 0x00;
+ erase.flight = ao_flight_number;
+ ao_storage_write(ao_log_erase_pos(pos), &erase, sizeof (erase));
+ ao_storage_flush();
+}
+
+static void
+ao_log_read_erase(uint8_t pos)
+{
+ ao_storage_read(ao_log_erase_pos(pos), &erase, sizeof (erase));
+}
+
+
+static void
+ao_log_erase_mark(void)
+{
+ uint8_t i;
+
+ for (i = 0; i < LOG_MAX_ERASE; i++) {
+ ao_log_read_erase(i);
+ if (erase.unused == 0 && erase.flight == ao_flight_number)
+ return;
+ if (erase.unused == 0xff) {
+ ao_log_write_erase(i);
+ return;
+ }
+ }
+ ao_config_put();
+}
+
+static uint8_t
+ao_log_slots()
+{
+ return (uint8_t) (ao_storage_config / ao_config.flight_log_max);
+}
+
+uint32_t
+ao_log_pos(uint8_t slot)
+{
+ return ((slot) * ao_config.flight_log_max);
+}
+
+static uint16_t
+ao_log_max_flight(void)
+{
+ uint8_t log_slot;
+ uint8_t log_slots;
+ uint16_t log_flight;
+ uint16_t max_flight = 0;
+
+ /* Scan the log space looking for the biggest flight number */
+ log_slots = ao_log_slots();
+ for (log_slot = 0; log_slot < log_slots; log_slot++) {
+ log_flight = ao_log_flight(log_slot);
+ if (!log_flight)
+ continue;
+ if (max_flight == 0 || (int16_t) (log_flight - max_flight) > 0)
+ max_flight = log_flight;
+ }
+ return max_flight;
+}
+
+void
+ao_log_scan(void) __reentrant
+{
+ uint8_t log_slot;
+ uint8_t log_slots;
+ uint8_t log_want;
+
+ ao_config_get();
+
+ ao_flight_number = ao_log_max_flight();
+ if (ao_flight_number)
+ if (++ao_flight_number == 0)
+ ao_flight_number = 1;
+
+ /* Now look through the log of flight numbers from erase operations and
+ * see if the last one is bigger than what we found above
+ */
+ for (log_slot = LOG_MAX_ERASE; log_slot-- > 0;) {
+ ao_log_read_erase(log_slot);
+ if (erase.unused == 0) {
+ if (ao_flight_number == 0 ||
+ (int16_t) (erase.flight - ao_flight_number) > 0)
+ ao_flight_number = erase.flight;
+ break;
+ }
+ }
+ if (ao_flight_number == 0)
+ ao_flight_number = 1;
+
+ /* With a flight number in hand, find a place to write a new log,
+ * use the target flight number to index the available log slots so
+ * that we write logs to each spot about the same number of times.
+ */
+
+ /* Find a log slot for the next flight, if available */
+ ao_log_current_pos = ao_log_end_pos = 0;
+ log_slots = ao_log_slots();
+ log_want = (ao_flight_number - 1) % log_slots;
+ log_slot = log_want;
+ do {
+ if (ao_log_flight(log_slot) == 0) {
+ ao_log_current_pos = ao_log_pos(log_slot);
+ ao_log_end_pos = ao_log_current_pos + ao_config.flight_log_max;
+ break;
+ }
+ if (++log_slot >= log_slots)
+ log_slot = 0;
+ } while (log_slot != log_want);
+
+ ao_wakeup(&ao_flight_number);
+}
+
+void
+ao_log_start(void)
+{
+ /* start logging */
+ ao_log_running = 1;
+ ao_wakeup(&ao_log_running);
+}
+
+void
+ao_log_stop(void)
+{
+ ao_log_running = 0;
+ ao_log_flush();
+}
+
+uint8_t
+ao_log_present(void)
+{
+ return ao_log_max_flight() != 0;
+}
+
+uint8_t
+ao_log_full(void)
+{
+ return ao_log_current_pos == ao_log_end_pos;
+}
+
+static __xdata struct ao_task ao_log_task;
+
+void
+ao_log_list(void) __reentrant
+{
+ uint8_t slot;
+ uint8_t slots;
+ uint16_t flight;
+
+ slots = ao_log_slots();
+ for (slot = 0; slot < slots; slot++)
+ {
+ flight = ao_log_flight(slot);
+ if (flight)
+ printf ("flight %d start %x end %x\n",
+ flight,
+ (uint16_t) (ao_log_pos(slot) >> 8),
+ (uint16_t) (ao_log_pos(slot+1) >> 8));
+ }
+ printf ("done\n");
+}
+
+void
+ao_log_delete(void) __reentrant
+{
+ uint8_t slot;
+ uint8_t slots;
+
+ ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+
+ slots = ao_log_slots();
+ /* Look for the flight log matching the requested flight */
+ if (ao_cmd_lex_i) {
+ for (slot = 0; slot < slots; slot++) {
+ if (ao_log_flight(slot) == ao_cmd_lex_i) {
+ ao_log_erase_mark();
+ ao_log_current_pos = ao_log_pos(slot);
+ ao_log_end_pos = ao_log_current_pos + ao_config.flight_log_max;
+ while (ao_log_current_pos < ao_log_end_pos) {
+ uint8_t i;
+ static __xdata uint8_t b;
+
+ /*
+ * Check to see if we've reached the end of
+ * the used memory to avoid re-erasing the same
+ * memory over and over again
+ */
+ for (i = 0; i < 16; i++) {
+ if (ao_storage_read(ao_log_current_pos + i, &b, 1))
+ if (b != 0xff)
+ break;
+ }
+ if (i == 16)
+ break;
+ ao_storage_erase(ao_log_current_pos);
+ ao_log_current_pos += ao_storage_block;
+ }
+ puts("Erased");
+ return;
+ }
+ }
+ }
+ printf("No such flight: %d\n", ao_cmd_lex_i);
+}
+
+__code struct ao_cmds ao_log_cmds[] = {
+ { ao_log_list, "l\0List flight logs" },
+ { ao_log_delete, "d <flight-number>\0Delete flight" },
+ { 0, NULL },
+};
+
+void
+ao_log_init(void)
+{
+ ao_log_running = 0;
+
+ /* For now, just log the flight starting at the begining of eeprom */
+ ao_log_state = ao_flight_invalid;
+
+ ao_cmd_register(&ao_log_cmds[0]);
+
+ /* Create a task to log events to eeprom */
+ ao_add_task(&ao_log_task, ao_log, "log");
+}
--- /dev/null
+/*
+ * 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"
+
+static __xdata uint8_t ao_log_mutex;
+static __xdata struct ao_log_record log;
+
+static uint8_t
+ao_log_csum(__xdata uint8_t *b) __reentrant
+{
+ uint8_t sum = 0x5a;
+ uint8_t i;
+
+ for (i = 0; i < sizeof (struct ao_log_record); i++)
+ sum += *b++;
+ return -sum;
+}
+
+uint8_t
+ao_log_data(__xdata struct ao_log_record *log) __reentrant
+{
+ uint8_t wrote = 0;
+ /* set checksum */
+ log->csum = 0;
+ log->csum = ao_log_csum((__xdata uint8_t *) log);
+ ao_mutex_get(&ao_log_mutex); {
+ if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
+ ao_log_stop();
+ if (ao_log_running) {
+ wrote = 1;
+ ao_storage_write(ao_log_current_pos,
+ log,
+ sizeof (struct ao_log_record));
+ ao_log_current_pos += sizeof (struct ao_log_record);
+ }
+ } ao_mutex_put(&ao_log_mutex);
+ return wrote;
+}
+
+static uint8_t
+ao_log_dump_check_data(void)
+{
+ if (ao_log_csum((uint8_t *) &log) != 0)
+ return 0;
+ return 1;
+}
+
+static __data uint8_t ao_log_adc_pos;
+
+/* a hack to make sure that ao_log_records fill the eeprom block in even units */
+typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_record))] ;
+
+#define AO_SENSOR_INTERVAL_ASCENT 1
+#define AO_SENSOR_INTERVAL_DESCENT 10
+#define AO_OTHER_INTERVAL 32
+
+void
+ao_log(void)
+{
+ __pdata uint16_t next_sensor, next_other;
+
+ ao_storage_setup();
+
+ ao_log_scan();
+
+ while (!ao_log_running)
+ ao_sleep(&ao_log_running);
+
+ log.type = AO_LOG_FLIGHT;
+ log.tick = ao_sample_tick;
+#if HAS_ACCEL
+ log.u.flight.ground_accel = ao_ground_accel;
+#endif
+ log.u.flight.flight = ao_flight_number;
+ ao_log_data(&log);
+
+ /* Write the whole contents of the ring to the log
+ * when starting up.
+ */
+ ao_log_adc_pos = ao_adc_ring_next(ao_sample_adc);
+ next_other = next_sensor = ao_adc_ring[ao_log_adc_pos].tick;
+ ao_log_state = ao_flight_startup;
+ for (;;) {
+ /* Write samples to EEPROM */
+ while (ao_log_adc_pos != ao_sample_adc) {
+ log.tick = ao_adc_ring[ao_log_adc_pos].tick;
+ if ((int16_t) (log.tick - next_sensor) >= 0) {
+ log.type = AO_LOG_SENSOR;
+ log.u.sensor.accel = ao_adc_ring[ao_log_adc_pos].accel;
+ log.u.sensor.pres = ao_adc_ring[ao_log_adc_pos].pres;
+ ao_log_data(&log);
+ if (ao_log_state <= ao_flight_coast)
+ next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT;
+ else
+ next_sensor = log.tick + AO_SENSOR_INTERVAL_DESCENT;
+ }
+ if ((int16_t) (log.tick - next_other) >= 0) {
+ log.type = AO_LOG_TEMP_VOLT;
+ log.u.temp_volt.temp = ao_adc_ring[ao_log_adc_pos].temp;
+ log.u.temp_volt.v_batt = ao_adc_ring[ao_log_adc_pos].v_batt;
+ ao_log_data(&log);
+ log.type = AO_LOG_DEPLOY;
+ log.u.deploy.drogue = ao_adc_ring[ao_log_adc_pos].sense_d;
+ log.u.deploy.main = ao_adc_ring[ao_log_adc_pos].sense_m;
+ ao_log_data(&log);
+ next_other = log.tick + AO_OTHER_INTERVAL;
+ }
+ ao_log_adc_pos = ao_adc_ring_next(ao_log_adc_pos);
+ }
+ /* Write state change to EEPROM */
+ if (ao_flight_state != ao_log_state) {
+ ao_log_state = ao_flight_state;
+ log.type = AO_LOG_STATE;
+ log.tick = ao_sample_tick;
+ log.u.state.state = ao_log_state;
+ log.u.state.reason = 0;
+ ao_log_data(&log);
+
+ if (ao_log_state == ao_flight_landed)
+ ao_log_stop();
+ }
+
+ /* Wait for a while */
+ ao_delay(AO_MS_TO_TICKS(100));
+
+ /* Stop logging when told to */
+ while (!ao_log_running)
+ ao_sleep(&ao_log_running);
+ }
+}
+
+uint16_t
+ao_log_flight(uint8_t slot)
+{
+ if (!ao_storage_read(ao_log_pos(slot),
+ &log,
+ sizeof (struct ao_log_record)))
+ return 0;
+
+ if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
+ return log.u.flight.flight;
+ return 0;
+}
--- /dev/null
+/*
+ * 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");
+}
--- /dev/null
+/*
+ * 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)
+{
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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"
+
+static __data uint16_t ao_log_tiny_interval;
+
+#define AO_LOG_TINY_INTERVAL_DEFAULT AO_MS_TO_TICKS(1000)
+#if USE_FAST_ASCENT_LOG
+#define AO_LOG_TINY_INTERVAL_ASCENT AO_MS_TO_TICKS(100)
+#define AO_PAD_RING 8
+#else
+#define AO_LOG_TINY_INTERVAL_ASCENT AO_LOG_TINY_INTERVAL_DEFAULT
+#define AO_PAD_RING 2
+#endif
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT_TINY;
+
+void
+ao_log_tiny_set_interval(uint16_t ticks)
+{
+ ao_log_tiny_interval = ticks;
+}
+
+
+static void ao_log_tiny_data(uint16_t d)
+{
+ if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
+ ao_log_stop();
+ if (ao_log_running) {
+ ao_storage_write(ao_log_current_pos, DATA_TO_XDATA(&d), 2);
+ ao_log_current_pos += 2;
+ }
+}
+
+static __xdata uint16_t ao_log_pad_ring[AO_PAD_RING];
+static __pdata uint8_t ao_log_pad_ring_pos;
+
+#define ao_pad_ring_next(n) (((n) + 1) & (AO_PAD_RING - 1))
+
+static void ao_log_tiny_queue(uint16_t d)
+{
+ ao_log_pad_ring[ao_log_pad_ring_pos] = d;
+ ao_log_pad_ring_pos = ao_pad_ring_next(ao_log_pad_ring_pos);
+}
+
+static void ao_log_tiny_start(void)
+{
+ uint8_t p;
+ uint16_t d;
+
+ ao_log_tiny_data(ao_flight_number);
+ ao_log_tiny_data(ao_ground_pres);
+ p = ao_log_pad_ring_pos;
+ do {
+ d = ao_log_pad_ring[p];
+ /*
+ * ignore unwritten slots
+ */
+ if (d)
+ ao_log_tiny_data(d);
+ p = ao_pad_ring_next(p);
+ } while (p != ao_log_pad_ring_pos);
+}
+
+void
+ao_log(void)
+{
+ uint16_t last_time;
+ uint16_t now;
+ enum ao_flight_state ao_log_tiny_state;
+ int32_t sum;
+ int16_t count;
+ uint8_t ao_log_adc;
+ uint8_t ao_log_started = 0;
+
+ ao_storage_setup();
+
+ ao_log_scan();
+
+ ao_log_tiny_state = ao_flight_invalid;
+ ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT;
+ sum = 0;
+ count = 0;
+ ao_log_adc = ao_sample_adc;
+ last_time = ao_time();
+ for (;;) {
+
+ /*
+ * Add in pending sample data
+ */
+ ao_sleep(DATA_TO_XDATA(&ao_sample_adc));
+ while (ao_log_adc != ao_sample_adc) {
+ sum += ao_adc_ring[ao_log_adc].pres;
+ count++;
+ ao_log_adc = ao_adc_ring_next(ao_log_adc);
+ }
+ if (ao_log_running) {
+ if (!ao_log_started) {
+ ao_log_tiny_start();
+ ao_log_started = 1;
+ }
+ if (ao_flight_state != ao_log_tiny_state) {
+ ao_log_tiny_data(ao_flight_state | 0x8000);
+ ao_log_tiny_state = ao_flight_state;
+ ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_DEFAULT;
+#if AO_LOG_TINY_INTERVAL_ASCENT != AO_LOG_TINY_INTERVAL_DEFAULT
+ if (ao_log_tiny_state <= ao_flight_coast)
+ ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT;
+#endif
+ if (ao_log_tiny_state == ao_flight_landed)
+ ao_log_stop();
+ }
+ }
+
+ /* Stop logging when told to */
+ if (!ao_log_running && ao_log_started)
+ ao_exit();
+
+ /*
+ * Write out the sample when finished
+ */
+ now = ao_time();
+ if ((int16_t) (now - (last_time + ao_log_tiny_interval)) >= 0 && count) {
+ count = sum / count;
+ if (ao_log_started)
+ ao_log_tiny_data(count);
+ else
+ ao_log_tiny_queue(count);
+ sum = 0;
+ count = 0;
+ last_time = now;
+ }
+ }
+}
+
+uint16_t
+ao_log_flight(uint8_t slot)
+{
+ static __xdata uint16_t flight;
+
+ (void) slot;
+ ao_storage_read(0, &flight, 2);
+ if (flight == 0xffff)
+ flight = 0;
+ return flight;
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_telem.h"
+
+#if !HAS_MONITOR
+#error Must define HAS_MONITOR to 1
+#endif
+
+__data uint8_t ao_monitoring;
+__pdata uint8_t ao_monitor_led;
+
+__xdata union ao_monitor ao_monitor_ring[AO_MONITOR_RING];
+
+__data uint8_t ao_monitor_head;
+
+void
+ao_monitor_get(void)
+{
+ uint8_t size;
+
+ for (;;) {
+ switch (ao_monitoring) {
+ case 0:
+ ao_sleep(DATA_TO_XDATA(&ao_monitoring));
+ continue;
+ case AO_MONITORING_ORIG:
+ size = sizeof (struct ao_telemetry_orig_recv);
+ break;
+ case AO_MONITORING_TINY:
+ size = sizeof (struct ao_telemetry_tiny_recv);
+ break;
+ default:
+ if (ao_monitoring > AO_MAX_TELEMETRY)
+ ao_monitoring = AO_MAX_TELEMETRY;
+ size = ao_monitoring;
+ break;
+ }
+ if (!ao_radio_recv(&ao_monitor_ring[ao_monitor_head], size + 2))
+ continue;
+ ao_monitor_head = ao_monitor_ring_next(ao_monitor_head);
+ ao_wakeup(DATA_TO_XDATA(&ao_monitor_head));
+ }
+}
+
+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));
+ }
+}
+
+void
+ao_monitor_put(void)
+{
+ __xdata char callsign[AO_MAX_CALLSIGN+1];
+
+ uint8_t ao_monitor_tail;
+ uint8_t state;
+ uint8_t sum, byte;
+ int16_t rssi;
+ __xdata union ao_monitor *m;
+
+#define recv_raw ((m->raw))
+#define recv_orig ((m->orig))
+#define recv_tiny ((m->tiny))
+
+ ao_monitor_tail = ao_monitor_head;
+ for (;;) {
+ while (ao_monitor_tail == ao_monitor_head)
+ ao_sleep(DATA_TO_XDATA(&ao_monitor_head));
+ m = &ao_monitor_ring[ao_monitor_tail];
+ ao_monitor_tail = ao_monitor_ring_next(ao_monitor_tail);
+ switch (ao_monitoring) {
+ case AO_MONITORING_ORIG:
+ state = recv_orig.telemetry_orig.flight_state;
+
+ /* Typical RSSI offset for 38.4kBaud at 433 MHz is 74 */
+ rssi = (int16_t) (recv_orig.rssi >> 1) - 74;
+ memcpy(callsign, recv_orig.telemetry_orig.callsign, AO_MAX_CALLSIGN);
+ if (state > ao_flight_invalid)
+ state = ao_flight_invalid;
+ if (recv_orig.status & PKT_APPEND_STATUS_1_CRC_OK) {
+
+ /* General header fields */
+ printf(AO_TELEM_VERSION " %d "
+ AO_TELEM_CALL " %s "
+ AO_TELEM_SERIAL " %d "
+ AO_TELEM_FLIGHT " %d "
+ AO_TELEM_RSSI " %d "
+ AO_TELEM_STATE " %s "
+ AO_TELEM_TICK " %d ",
+ AO_TELEMETRY_VERSION,
+ callsign,
+ recv_orig.telemetry_orig.serial,
+ recv_orig.telemetry_orig.flight,
+ rssi,
+ ao_state_names[state],
+ recv_orig.telemetry_orig.adc.tick);
+
+ /* Raw sensor values */
+ printf(AO_TELEM_RAW_ACCEL " %d "
+ AO_TELEM_RAW_BARO " %d "
+ AO_TELEM_RAW_THERMO " %d "
+ AO_TELEM_RAW_BATT " %d "
+ AO_TELEM_RAW_DROGUE " %d "
+ AO_TELEM_RAW_MAIN " %d ",
+ recv_orig.telemetry_orig.adc.accel,
+ recv_orig.telemetry_orig.adc.pres,
+ recv_orig.telemetry_orig.adc.temp,
+ recv_orig.telemetry_orig.adc.v_batt,
+ recv_orig.telemetry_orig.adc.sense_d,
+ recv_orig.telemetry_orig.adc.sense_m);
+
+ /* Sensor calibration values */
+ printf(AO_TELEM_CAL_ACCEL_GROUND " %d "
+ AO_TELEM_CAL_BARO_GROUND " %d "
+ AO_TELEM_CAL_ACCEL_PLUS " %d "
+ AO_TELEM_CAL_ACCEL_MINUS " %d ",
+ recv_orig.telemetry_orig.ground_accel,
+ recv_orig.telemetry_orig.ground_pres,
+ recv_orig.telemetry_orig.accel_plus_g,
+ recv_orig.telemetry_orig.accel_minus_g);
+
+ if (recv_orig.telemetry_orig.u.k.unused == 0x8000) {
+ /* Kalman state values */
+ printf(AO_TELEM_KALMAN_HEIGHT " %d "
+ AO_TELEM_KALMAN_SPEED " %d "
+ AO_TELEM_KALMAN_ACCEL " %d ",
+ recv_orig.telemetry_orig.height,
+ recv_orig.telemetry_orig.u.k.speed,
+ recv_orig.telemetry_orig.accel);
+ } else {
+ /* Ad-hoc flight values */
+ printf(AO_TELEM_ADHOC_ACCEL " %d "
+ AO_TELEM_ADHOC_SPEED " %ld "
+ AO_TELEM_ADHOC_BARO " %d ",
+ recv_orig.telemetry_orig.accel,
+ recv_orig.telemetry_orig.u.flight_vel,
+ recv_orig.telemetry_orig.height);
+ }
+ 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);
+ }
+ break;
+ case AO_MONITORING_TINY:
+ state = recv_tiny.telemetry_tiny.flight_state;
+
+ /* Typical RSSI offset for 38.4kBaud at 433 MHz is 74 */
+ rssi = (int16_t) (recv_tiny.rssi >> 1) - 74;
+ memcpy(callsign, recv_tiny.telemetry_tiny.callsign, AO_MAX_CALLSIGN);
+ if (state > ao_flight_invalid)
+ state = ao_flight_invalid;
+ if (recv_tiny.status & PKT_APPEND_STATUS_1_CRC_OK) {
+ /* General header fields */
+ printf(AO_TELEM_VERSION " %d "
+ AO_TELEM_CALL " %s "
+ AO_TELEM_SERIAL " %d "
+ AO_TELEM_FLIGHT " %d "
+ AO_TELEM_RSSI " %d "
+ AO_TELEM_STATE " %s "
+ AO_TELEM_TICK " %d ",
+ AO_TELEMETRY_VERSION,
+ callsign,
+ recv_tiny.telemetry_tiny.serial,
+ recv_tiny.telemetry_tiny.flight,
+ rssi,
+ ao_state_names[state],
+ recv_tiny.telemetry_tiny.adc.tick);
+
+ /* Raw sensor values */
+ printf(AO_TELEM_RAW_BARO " %d "
+ AO_TELEM_RAW_THERMO " %d "
+ AO_TELEM_RAW_BATT " %d "
+ AO_TELEM_RAW_DROGUE " %d "
+ AO_TELEM_RAW_MAIN " %d ",
+ recv_tiny.telemetry_tiny.adc.pres,
+ recv_tiny.telemetry_tiny.adc.temp,
+ recv_tiny.telemetry_tiny.adc.v_batt,
+ recv_tiny.telemetry_tiny.adc.sense_d,
+ recv_tiny.telemetry_tiny.adc.sense_m);
+
+ /* Sensor calibration values */
+ printf(AO_TELEM_CAL_BARO_GROUND " %d ",
+ recv_tiny.telemetry_tiny.ground_pres);
+
+#if 1
+ /* Kalman state values */
+ printf(AO_TELEM_KALMAN_HEIGHT " %d "
+ AO_TELEM_KALMAN_SPEED " %d "
+ AO_TELEM_KALMAN_ACCEL " %d\n",
+ recv_tiny.telemetry_tiny.height,
+ recv_tiny.telemetry_tiny.speed,
+ recv_tiny.telemetry_tiny.accel);
+#else
+ /* Ad-hoc flight values */
+ printf(AO_TELEM_ADHOC_ACCEL " %d "
+ AO_TELEM_ADHOC_SPEED " %ld "
+ AO_TELEM_ADHOC_BARO " %d\n",
+ recv_tiny.telemetry_tiny.flight_accel,
+ 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);
+ }
+ break;
+ default:
+ printf ("TELEM %02x", ao_monitoring + 2);
+ sum = 0x5a;
+ for (state = 0; state < ao_monitoring + 2; state++) {
+ byte = recv_raw.packet[state];
+ sum += byte;
+ 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();
+ }
+}
+
+__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)
+{
+ if (ao_monitoring)
+ ao_radio_recv_abort();
+ ao_monitoring = monitoring;
+ ao_wakeup(DATA_TO_XDATA(&ao_monitoring));
+}
+
+static void
+set_monitor(void)
+{
+ ao_cmd_hex();
+ ao_set_monitor(ao_cmd_lex_i);
+}
+
+__code struct ao_cmds ao_monitor_cmds[] = {
+ { set_monitor, "m <0 off, 1 full, 2 tiny>\0Enable/disable radio monitoring" },
+ { 0, NULL },
+};
+
+void
+ao_monitor_init(uint8_t monitor_led, uint8_t monitoring) __reentrant
+{
+ ao_monitor_led = monitor_led;
+ ao_monitoring = monitoring;
+ 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");
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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
+ao_mutex_get(__xdata uint8_t *mutex) __reentrant
+{
+ if (*mutex == ao_cur_task->task_id)
+ ao_panic(AO_PANIC_MUTEX);
+ __critical {
+ while (*mutex)
+ ao_sleep(mutex);
+ *mutex = ao_cur_task->task_id;
+ }
+}
+
+void
+ao_mutex_put(__xdata uint8_t *mutex) __reentrant
+{
+ if (*mutex != ao_cur_task->task_id)
+ ao_panic(AO_PANIC_MUTEX);
+ __critical {
+ *mutex = 0;
+ ao_wakeup(mutex);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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"
+
+#ifndef HAS_BEEP
+#error Please define HAS_BEEP
+#endif
+
+#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)
+{
+ uint8_t i = 0, j = 0;
+
+ while (n--)
+ while (--j)
+ while (--i)
+ ao_arch_nop();
+}
+
+void
+ao_panic(uint8_t reason)
+{
+ uint8_t n;
+
+ __critical for (;;) {
+ ao_panic_delay(20);
+ for (n = 0; n < 5; n++) {
+ ao_led_on(AO_LED_RED);
+ ao_beep(AO_BEEP_HIGH);
+ ao_panic_delay(1);
+ ao_led_off(AO_LED_RED);
+ ao_beep(AO_BEEP_LOW);
+ ao_panic_delay(1);
+ }
+ 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);
+ ao_panic_delay(10);
+ ao_led_off(AO_LED_RED);
+ ao_beep(AO_BEEP_OFF);
+ ao_panic_delay(10);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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"
+
+/* Defines which mark this particular AltOS product */
+
+const char ao_version[AO_MAX_VERSION] = AO_iVersion_STRING;
+const char ao_manufacturer[] = AO_iManufacturer_STRING;
+const char ao_product[] = AO_iProduct_STRING;
+
+#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8))
+
+#if HAS_USB
+#include "ao_usb.h"
+/* USB descriptors in one giant block of bytes */
+__code __at(0x00aa) uint8_t ao_usb_descriptors [] =
+{
+ /* Device descriptor */
+ 0x12,
+ AO_USB_DESC_DEVICE,
+ LE_WORD(0x0110), /* bcdUSB */
+ 0x02, /* bDeviceClass */
+ 0x00, /* bDeviceSubClass */
+ 0x00, /* bDeviceProtocol */
+ AO_USB_CONTROL_SIZE, /* bMaxPacketSize */
+ LE_WORD(0xFFFE), /* idVendor */
+ LE_WORD(AO_idProduct_NUMBER), /* idProduct */
+ LE_WORD(0x0100), /* bcdDevice */
+ 0x01, /* iManufacturer */
+ 0x02, /* iProduct */
+ 0x03, /* iSerialNumber */
+ 0x01, /* bNumConfigurations */
+
+ /* Configuration descriptor */
+ 0x09,
+ AO_USB_DESC_CONFIGURATION,
+ LE_WORD(67), /* wTotalLength */
+ 0x02, /* bNumInterfaces */
+ 0x01, /* bConfigurationValue */
+ 0x00, /* iConfiguration */
+ 0xC0, /* bmAttributes */
+ 0x32, /* bMaxPower */
+
+ /* Control class interface */
+ 0x09,
+ AO_USB_DESC_INTERFACE,
+ 0x00, /* bInterfaceNumber */
+ 0x00, /* bAlternateSetting */
+ 0x01, /* bNumEndPoints */
+ 0x02, /* bInterfaceClass */
+ 0x02, /* bInterfaceSubClass */
+ 0x01, /* bInterfaceProtocol, linux requires value of 1 for the cdc_acm module */
+ 0x00, /* iInterface */
+
+ /* Header functional descriptor */
+ 0x05,
+ CS_INTERFACE,
+ 0x00, /* bDescriptor SubType Header */
+ LE_WORD(0x0110), /* CDC version 1.1 */
+
+ /* Call management functional descriptor */
+ 0x05,
+ CS_INTERFACE,
+ 0x01, /* bDescriptor SubType Call Management */
+ 0x01, /* bmCapabilities = device handles call management */
+ 0x01, /* bDataInterface call management interface number */
+
+ /* ACM functional descriptor */
+ 0x04,
+ CS_INTERFACE,
+ 0x02, /* bDescriptor SubType Abstract Control Management */
+ 0x02, /* bmCapabilities = D1 (Set_line_Coding, Set_Control_Line_State, Get_Line_Coding and Serial_State) */
+
+ /* Union functional descriptor */
+ 0x05,
+ CS_INTERFACE,
+ 0x06, /* bDescriptor SubType Union Functional descriptor */
+ 0x00, /* bMasterInterface */
+ 0x01, /* bSlaveInterface0 */
+
+ /* Notification EP */
+ 0x07,
+ AO_USB_DESC_ENDPOINT,
+ AO_USB_INT_EP|0x80, /* bEndpointAddress */
+ 0x03, /* bmAttributes = intr */
+ LE_WORD(8), /* wMaxPacketSize */
+ 0x0A, /* bInterval */
+
+ /* Data class interface descriptor */
+ 0x09,
+ AO_USB_DESC_INTERFACE,
+ 0x01, /* bInterfaceNumber */
+ 0x00, /* bAlternateSetting */
+ 0x02, /* bNumEndPoints */
+ 0x0A, /* bInterfaceClass = data */
+ 0x00, /* bInterfaceSubClass */
+ 0x00, /* bInterfaceProtocol */
+ 0x00, /* iInterface */
+
+ /* Data EP OUT */
+ 0x07,
+ AO_USB_DESC_ENDPOINT,
+ AO_USB_OUT_EP, /* bEndpointAddress */
+ 0x02, /* bmAttributes = bulk */
+ LE_WORD(AO_USB_OUT_SIZE),/* wMaxPacketSize */
+ 0x00, /* bInterval */
+
+ /* Data EP in */
+ 0x07,
+ AO_USB_DESC_ENDPOINT,
+ AO_USB_IN_EP|0x80, /* bEndpointAddress */
+ 0x02, /* bmAttributes = bulk */
+ LE_WORD(AO_USB_IN_SIZE),/* wMaxPacketSize */
+ 0x00, /* bInterval */
+
+ /* String descriptors */
+ 0x04,
+ AO_USB_DESC_STRING,
+ LE_WORD(0x0409),
+
+ /* iManufacturer */
+ AO_iManufacturer_LEN,
+ AO_USB_DESC_STRING,
+ AO_iManufacturer_UCS2,
+
+ /* iProduct */
+ AO_iProduct_LEN,
+ AO_USB_DESC_STRING,
+ AO_iProduct_UCS2,
+
+ /* iSerial */
+ AO_iSerial_LEN,
+ AO_USB_DESC_STRING,
+ AO_iSerial_UCS2,
+
+ /* Terminating zero */
+ 0
+};
+#endif
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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 BIT(i,x) ((x) ? (1 << (i)) : 0)
+#define MORSE1(a) (1 | BIT(3,a))
+#define MORSE2(a,b) (2 | BIT(3,a) | BIT(4,b))
+#define MORSE3(a,b,c) (3 | BIT(3,a) | BIT(4,b) | BIT(5,c))
+#define MORSE4(a,b,c,d) (4 | BIT(3,a) | BIT(4,b) | BIT(5,c) | BIT(6,d))
+#define MORSE5(a,b,c,d,e) (5 | BIT(3,a) | BIT(4,b) | BIT(5,c) | BIT(6,d) | BIT(7,e))
+
+static const uint8_t flight_reports[] = {
+ MORSE3(0,0,0), /* startup, 'S' */
+ MORSE2(0,0), /* idle 'I' */
+ MORSE4(0,1,1,0), /* pad 'P' */
+ MORSE4(1,0,0,0), /* boost 'B' */
+ MORSE4(0,0,1,0), /* fast 'F' */
+ MORSE4(1,0,1,0), /* coast 'C' */
+ MORSE3(1,0,0), /* drogue 'D' */
+ MORSE2(1,1), /* main 'M' */
+ MORSE4(0,1,0,0), /* landed 'L' */
+ MORSE4(1,0,0,1), /* invalid 'X' */
+};
+
+#if HAS_BEEP
+#define low(time) ao_beep_for(AO_BEEP_LOW, time)
+#define mid(time) ao_beep_for(AO_BEEP_MID, time)
+#define high(time) ao_beep_for(AO_BEEP_HIGH, time)
+#else
+#define low(time) ao_led_for(AO_LED_GREEN, time)
+#define mid(time) ao_led_for(AO_LED_RED, time)
+#define high(time) ao_led_for(AO_LED_GREEN|AO_LED_RED, time)
+#endif
+#define pause(time) ao_delay(time)
+
+static __pdata enum ao_flight_state ao_report_state;
+
+static void
+ao_report_beep(void) __reentrant
+{
+ uint8_t r = flight_reports[ao_flight_state];
+ uint8_t l = r & 7;
+
+ if (!r)
+ return;
+ while (l--) {
+ if (r & 8)
+ mid(AO_MS_TO_TICKS(600));
+ else
+ mid(AO_MS_TO_TICKS(200));
+ pause(AO_MS_TO_TICKS(200));
+ r >>= 1;
+ }
+ pause(AO_MS_TO_TICKS(400));
+}
+
+static void
+ao_report_digit(uint8_t digit) __reentrant
+{
+ if (!digit) {
+ mid(AO_MS_TO_TICKS(500));
+ pause(AO_MS_TO_TICKS(200));
+ } else {
+ while (digit--) {
+ mid(AO_MS_TO_TICKS(200));
+ pause(AO_MS_TO_TICKS(200));
+ }
+ }
+ pause(AO_MS_TO_TICKS(300));
+}
+
+static void
+ao_report_altitude(void)
+{
+ __pdata int16_t agl = ao_max_height;
+ __xdata uint8_t digits[10];
+ __pdata uint8_t ndigits, i;
+
+ if (agl < 0)
+ agl = 0;
+ ndigits = 0;
+ do {
+ digits[ndigits++] = agl % 10;
+ agl /= 10;
+ } while (agl);
+
+ for (;;) {
+ ao_report_beep();
+ i = ndigits;
+ do
+ ao_report_digit(digits[--i]);
+ while (i != 0);
+ pause(AO_SEC_TO_TICKS(5));
+ }
+}
+
+#if HAS_IGNITE_REPORT
+static uint8_t
+ao_report_igniter_ready(enum ao_igniter igniter)
+{
+ return ao_igniter_status(igniter) == ao_igniter_ready ? 1 : 0;
+}
+
+static void
+ao_report_continuity(void) __reentrant
+{
+ 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--) {
+ high(AO_MS_TO_TICKS(25));
+ pause(AO_MS_TO_TICKS(100));
+ }
+ } else {
+ c = 10;
+ while (c--) {
+ high(AO_MS_TO_TICKS(20));
+ low(AO_MS_TO_TICKS(20));
+ }
+ }
+#if HAS_LOG
+ if (ao_log_full()) {
+ pause(AO_MS_TO_TICKS(100));
+ c = 2;
+ while (c--) {
+ low(AO_MS_TO_TICKS(100));
+ mid(AO_MS_TO_TICKS(100));
+ high(AO_MS_TO_TICKS(100));
+ mid(AO_MS_TO_TICKS(100));
+ }
+ }
+#endif
+}
+#endif
+
+void
+ao_report(void)
+{
+ ao_report_state = ao_flight_state;
+ for(;;) {
+ if (ao_flight_state == ao_flight_landed)
+ ao_report_altitude();
+ ao_report_beep();
+#if HAS_IGNITE_REPORT
+ if (ao_flight_state == ao_flight_idle)
+ ao_report_continuity();
+ 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)
+ ao_sleep(DATA_TO_XDATA(&ao_flight_state));
+ ao_report_state = ao_flight_state;
+ }
+ }
+}
+
+static __xdata struct ao_task ao_report_task;
+
+void
+ao_report_init(void)
+{
+ ao_add_task(&ao_report_task, ao_report, "report");
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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 __xdata volatile uint16_t ao_rssi_time;
+static __pdata volatile uint16_t ao_rssi_delay;
+static __pdata uint8_t ao_rssi_led;
+
+void
+ao_rssi(void)
+{
+ for (;;) {
+ while ((int16_t) (ao_time() - ao_rssi_time) > AO_SEC_TO_TICKS(3))
+ ao_sleep(&ao_rssi_time);
+ ao_led_for(ao_rssi_led, AO_MS_TO_TICKS(100));
+ ao_delay(ao_rssi_delay);
+ }
+}
+
+void
+ao_rssi_set(int rssi_value)
+{
+ if (rssi_value > 0)
+ rssi_value = 0;
+ ao_rssi_delay = AO_MS_TO_TICKS((-rssi_value) * 5);
+ ao_rssi_time = ao_time();
+ ao_wakeup(&ao_rssi_time);
+}
+
+__xdata struct ao_task ao_rssi_task;
+
+void
+ao_rssi_init(uint8_t rssi_led)
+{
+ ao_rssi_led = rssi_led;
+ ao_rssi_delay = 0;
+ ao_add_task(&ao_rssi_task, ao_rssi, "rssi");
+}
--- /dev/null
+/*
+ * 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_FLIGHT_TEST
+#include "ao.h"
+#endif
+
+/*
+ * Current sensor values
+ */
+
+__pdata uint16_t ao_sample_tick; /* time of last data */
+__pdata int16_t ao_sample_pres;
+__pdata int16_t ao_sample_alt;
+__pdata int16_t ao_sample_height;
+#if HAS_ACCEL
+__pdata int16_t ao_sample_accel;
+#endif
+
+__data uint8_t ao_sample_adc;
+
+/*
+ * Sensor calibration values
+ */
+
+__pdata int16_t ao_ground_pres; /* startup pressure */
+__pdata int16_t ao_ground_height; /* MSL of ao_ground_pres */
+
+#if HAS_ACCEL
+__pdata int16_t ao_ground_accel; /* startup acceleration */
+__pdata int16_t ao_accel_2g; /* factory accel calibration */
+__pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */
+#endif
+
+static __pdata uint8_t ao_preflight; /* in preflight mode */
+
+static __pdata uint16_t nsamples;
+__pdata int32_t ao_sample_pres_sum;
+#if HAS_ACCEL
+__pdata int32_t ao_sample_accel_sum;
+#endif
+
+static void
+ao_sample_preflight(void)
+{
+ /* startup state:
+ *
+ * Collect 512 samples of acceleration and pressure
+ * data and average them to find the resting values
+ */
+ if (nsamples < 512) {
+#if HAS_ACCEL
+ ao_sample_accel_sum += ao_sample_accel;
+#endif
+ ao_sample_pres_sum += ao_sample_pres;
+ ++nsamples;
+ } else {
+ ao_config_get();
+#if HAS_ACCEL
+ ao_ground_accel = ao_sample_accel_sum >> 9;
+ ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g;
+ ao_accel_scale = to_fix32(GRAVITY * 2 * 16) / ao_accel_2g;
+#endif
+ ao_ground_pres = ao_sample_pres_sum >> 9;
+ ao_ground_height = ao_pres_to_altitude(ao_ground_pres);
+ ao_preflight = FALSE;
+ }
+}
+
+uint8_t
+ao_sample(void)
+{
+ ao_wakeup(DATA_TO_XDATA(&ao_sample_adc));
+ ao_sleep(DATA_TO_XDATA(&ao_adc_head));
+ while (ao_sample_adc != ao_adc_head) {
+ __xdata struct ao_adc *ao_adc;
+
+ /* Capture a sample */
+ ao_adc = &ao_adc_ring[ao_sample_adc];
+ ao_sample_tick = ao_adc->tick;
+ ao_sample_pres = ao_adc->pres;
+ ao_sample_alt = ao_pres_to_altitude(ao_sample_pres);
+ ao_sample_height = ao_sample_alt - ao_ground_height;
+#if HAS_ACCEL
+ ao_sample_accel = ao_adc->accel;
+#if HAS_ACCEL_REF
+ /*
+ * Ok, the math here is a bit tricky.
+ *
+ * ao_sample_accel: ADC output for acceleration
+ * ao_accel_ref: ADC output for the 5V reference.
+ * ao_cook_accel: Corrected acceleration value
+ * Vcc: 3.3V supply to the CC1111
+ * Vac: 5V supply to the accelerometer
+ * accel: input voltage to accelerometer ADC pin
+ * ref: input voltage to 5V reference ADC pin
+ *
+ *
+ * Measured acceleration is ratiometric to Vcc:
+ *
+ * ao_sample_accel accel
+ * ------------ = -----
+ * 32767 Vcc
+ *
+ * Measured 5v reference is also ratiometric to Vcc:
+ *
+ * ao_accel_ref ref
+ * ------------ = -----
+ * 32767 Vcc
+ *
+ *
+ * ao_accel_ref = 32767 * (ref / Vcc)
+ *
+ * Acceleration is measured ratiometric to the 5V supply,
+ * so what we want is:
+ *
+ * ao_cook_accel accel
+ * ------------- = -----
+ * 32767 ref
+ *
+ *
+ * accel Vcc
+ * = ----- * ---
+ * Vcc ref
+ *
+ * ao_sample_accel 32767
+ * = ------------ * ------------
+ * 32767 ao_accel_ref
+ *
+ * Multiply through by 32767:
+ *
+ * ao_sample_accel * 32767
+ * ao_cook_accel = --------------------
+ * ao_accel_ref
+ *
+ * Now, the tricky part. Getting this to compile efficiently
+ * and keeping all of the values in-range.
+ *
+ * First off, we need to use a shift of 16 instead of * 32767 as SDCC
+ * does the obvious optimizations for byte-granularity shifts:
+ *
+ * ao_cook_accel = (ao_sample_accel << 16) / ao_accel_ref
+ *
+ * Next, lets check our input ranges:
+ *
+ * 0 <= ao_sample_accel <= 0x7fff (singled ended ADC conversion)
+ * 0x7000 <= ao_accel_ref <= 0x7fff (the 5V ref value is close to 0x7fff)
+ *
+ * Plugging in our input ranges, we get an output range of 0 - 0x12490,
+ * which is 17 bits. That won't work. If we take the accel ref and shift
+ * by a bit, we'll change its range:
+ *
+ * 0xe000 <= ao_accel_ref<<1 <= 0xfffe
+ *
+ * ao_cook_accel = (ao_sample_accel << 16) / (ao_accel_ref << 1)
+ *
+ * Now the output range is 0 - 0x9248, which nicely fits in 16 bits. It
+ * is, however, one bit too large for our signed computations. So, we
+ * take the result and shift that by a bit:
+ *
+ * ao_cook_accel = ((ao_sample_accel << 16) / (ao_accel_ref << 1)) >> 1
+ *
+ * This finally creates an output range of 0 - 0x4924. As the ADC only
+ * provides 11 bits of data, we haven't actually lost any precision,
+ * just dropped a bit of noise off the low end.
+ */
+ ao_sample_accel = (uint16_t) ((((uint32_t) ao_sample_accel << 16) / (ao_accel_ref[ao_sample_adc] << 1))) >> 1;
+ if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP)
+ ao_sample_accel = 0x7fff - ao_sample_accel;
+ ao_adc->accel = ao_sample_accel;
+#endif
+#endif
+
+ if (ao_preflight)
+ ao_sample_preflight();
+ else
+ ao_kalman();
+ ao_sample_adc = ao_adc_ring_next(ao_sample_adc);
+ }
+ return !ao_preflight;
+}
+
+void
+ao_sample_init(void)
+{
+ nsamples = 0;
+ ao_sample_pres_sum = 0;
+ ao_sample_pres = 0;
+#if HAS_ACCEL
+ ao_sample_accel_sum = 0;
+ ao_sample_accel = 0;
+#endif
+ ao_sample_adc = ao_adc_head;
+ ao_preflight = TRUE;
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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"
+
+const char const * const ao_state_names[] = {
+ "startup", "idle", "pad", "boost", "fast",
+ "coast", "drogue", "main", "landed", "invalid"
+};
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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"
+
+/*
+ * Basic I/O functions to support SDCC stdio package
+ */
+
+#define AO_NUM_STDIOS (HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN)
+
+__xdata struct ao_stdio ao_stdios[AO_NUM_STDIOS];
+__pdata int8_t ao_cur_stdio;
+__pdata int8_t ao_num_stdios;
+
+void
+putchar(char c)
+{
+ if (c == '\n')
+ (*ao_stdios[ao_cur_stdio].putchar)('\r');
+ (*ao_stdios[ao_cur_stdio].putchar)(c);
+}
+
+void
+flush(void)
+{
+ if (ao_stdios[ao_cur_stdio].flush)
+ ao_stdios[ao_cur_stdio].flush();
+}
+
+__xdata uint8_t ao_stdin_ready;
+
+char
+getchar(void) __reentrant __critical
+{
+ char c;
+ int8_t stdio = ao_cur_stdio;
+
+ for (;;) {
+ c = ao_stdios[stdio].pollchar();
+ if (c != AO_READ_AGAIN)
+ break;
+ if (++stdio == ao_num_stdios)
+ stdio = 0;
+ if (stdio == ao_cur_stdio)
+ ao_sleep(&ao_stdin_ready);
+ }
+ ao_cur_stdio = stdio;
+ return c;
+}
+
+uint8_t
+ao_echo(void)
+{
+ return ao_stdios[ao_cur_stdio].echo;
+}
+
+int8_t
+ao_add_stdio(char (*pollchar)(void),
+ void (*putchar)(char),
+ void (*flush)(void)) __reentrant
+{
+ if (ao_num_stdios == AO_NUM_STDIOS)
+ ao_panic(AO_PANIC_STDIO);
+ ao_stdios[ao_num_stdios].pollchar = pollchar;
+ ao_stdios[ao_num_stdios].putchar = putchar;
+ ao_stdios[ao_num_stdios].flush = flush;
+ ao_stdios[ao_num_stdios].echo = 1;
+ return ao_num_stdios++;
+}
--- /dev/null
+/*
+ * 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_storage_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
+{
+ uint16_t this_len;
+ uint16_t this_off;
+
+ ao_storage_setup();
+ if (pos >= ao_storage_total || pos + len > ao_storage_total)
+ return 0;
+ while (len) {
+
+ /* Compute portion of transfer within
+ * a single block
+ */
+ this_off = (uint16_t) pos & (ao_storage_unit - 1);
+ this_len = ao_storage_unit - this_off;
+ if (this_len > len)
+ this_len = len;
+
+ if (!ao_storage_device_read(pos, buf, this_len))
+ return 0;
+
+ /* See how much is left */
+ buf += this_len;
+ len -= this_len;
+ pos += this_len;
+ }
+ return 1;
+}
+
+uint8_t
+ao_storage_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
+{
+ uint16_t this_len;
+ uint16_t this_off;
+
+ ao_storage_setup();
+ if (pos >= ao_storage_total || pos + len > ao_storage_total)
+ return 0;
+ while (len) {
+
+ /* Compute portion of transfer within
+ * a single block
+ */
+ this_off = (uint16_t) pos & (ao_storage_unit - 1);
+ this_len = ao_storage_unit - this_off;
+ if (this_len > len)
+ this_len = len;
+
+ if (!ao_storage_device_write(pos, buf, this_len))
+ return 0;
+
+ /* See how much is left */
+ buf += this_len;
+ len -= this_len;
+ pos += this_len;
+ }
+ return 1;
+}
+
+static __xdata uint8_t storage_data[8];
+
+static void
+ao_storage_dump(void) __reentrant
+{
+ uint8_t i, j;
+
+ ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ for (i = 0; ; i += 8) {
+ if (ao_storage_read(((uint32_t) (ao_cmd_lex_i) << 8) + i,
+ storage_data,
+ 8)) {
+ ao_cmd_put16((uint16_t) i);
+ for (j = 0; j < 8; j++) {
+ putchar(' ');
+ ao_cmd_put8(storage_data[j]);
+ }
+ putchar ('\n');
+ }
+ if (i == 248)
+ break;
+ }
+}
+
+#if 0
+
+/* not enough space for this today
+ */
+static void
+ao_storage_store(void) __reentrant
+{
+ uint16_t block;
+ uint8_t i;
+ uint16_t len;
+ static __xdata uint8_t b;
+ uint32_t addr;
+
+ ao_cmd_hex();
+ block = ao_cmd_lex_i;
+ ao_cmd_hex();
+ i = ao_cmd_lex_i;
+ addr = ((uint32_t) block << 8) | i;
+ ao_cmd_hex();
+ len = ao_cmd_lex_i;
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ while (len--) {
+ ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ b = ao_cmd_lex_i;
+ ao_storage_write(addr, &b, 1);
+ addr++;
+ }
+}
+#endif
+
+void
+ao_storage_zap(void) __reentrant
+{
+ ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ ao_storage_erase((uint32_t) ao_cmd_lex_i << 8);
+}
+
+void
+ao_storage_zapall(void) __reentrant
+{
+ uint32_t pos;
+
+ ao_cmd_white();
+ if (!ao_match_word("DoIt"))
+ return;
+ for (pos = 0; pos < ao_storage_config; pos += ao_storage_block)
+ ao_storage_erase(pos);
+}
+
+void
+ao_storage_info(void) __reentrant
+{
+ printf("Storage size: %ld\n", ao_storage_total);
+ printf("Storage erase unit: %ld\n", ao_storage_block);
+ ao_storage_device_info();
+}
+
+__code struct ao_cmds ao_storage_cmds[] = {
+ { ao_storage_info, "f\0Show storage" },
+ { ao_storage_dump, "e <block>\0Dump flash" },
+#ifdef HAS_STORAGE_DBG
+ { ao_storage_store, "w <block> <start> <len> <data> ...\0Write data to flash" },
+#endif
+ { ao_storage_zap, "z <block>\0Erase <block>" },
+ { ao_storage_zapall,"Z <key>\0Erase all. <key> is doit with D&I" },
+ { 0, NULL },
+};
+
+void
+ao_storage_init(void)
+{
+ ao_storage_device_init();
+ ao_cmd_register(&ao_storage_cmds[0]);
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_NO_TASK_INDEX 0xff
+
+__xdata struct ao_task * __xdata ao_tasks[AO_NUM_TASKS];
+__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 task_id;
+ uint8_t t;
+ if (ao_num_tasks == AO_NUM_TASKS)
+ ao_panic(AO_PANIC_NO_TASK);
+ for (task_id = 1; task_id != 0; task_id++) {
+ for (t = 0; t < ao_num_tasks; t++)
+ if (ao_tasks[t]->task_id == task_id)
+ break;
+ if (t == ao_num_tasks)
+ break;
+ }
+ 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
+ */
+ ao_arch_init_stack(task, start);
+}
+
+/* Task switching function. This must not use any stack variables */
+void
+ao_yield(void) ao_arch_naked_define
+{
+ ao_arch_save_regs();
+
+ if (ao_cur_task_index == AO_NO_TASK_INDEX)
+ ao_cur_task_index = ao_num_tasks-1;
+ else
+ {
+ ao_arch_save_stack();
+ }
+
+ 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
+ */
+ {
+ __pdata uint8_t ao_next_task_index = ao_cur_task_index;
+ for (;;) {
+ ++ao_next_task_index;
+ if (ao_next_task_index == ao_num_tasks)
+ ao_next_task_index = 0;
+
+ ao_cur_task = ao_tasks[ao_next_task_index];
+ if (ao_cur_task->wchan == NULL) {
+ ao_cur_task_index = ao_next_task_index;
+ break;
+ }
+
+ /* Check if the alarm is set for a time which has passed */
+ if (ao_cur_task->alarm &&
+ (int16_t) (ao_time() - ao_cur_task->alarm) >= 0) {
+ ao_cur_task_index = ao_next_task_index;
+ break;
+ }
+
+ /* Enter lower power mode when there isn't anything to do */
+ if (ao_next_task_index == ao_cur_task_index) {
+ ao_arch_cpu_idle();
+ }
+ }
+ }
+ ao_arch_restore_stack();
+}
+
+uint8_t
+ao_sleep(__xdata void *wchan)
+{
+ ao_arch_critical(
+ ao_cur_task->wchan = wchan;
+ );
+ ao_yield();
+ if (ao_cur_task->wchan) {
+ ao_cur_task->wchan = NULL;
+ return 1;
+ }
+ return 0;
+}
+
+void
+ao_wakeup(__xdata void *wchan)
+{
+ uint8_t i;
+
+ for (i = 0; i < ao_num_tasks; i++)
+ if (ao_tasks[i]->wchan == wchan)
+ ao_tasks[i]->wchan = NULL;
+}
+
+void
+ao_alarm(uint16_t delay)
+{
+ /* Make sure we sleep *at least* delay ticks, which means adding
+ * one to account for the fact that we may be close to the next tick
+ */
+ if (!(ao_cur_task->alarm = ao_time() + delay + 1))
+ ao_cur_task->alarm = 1;
+}
+
+void
+ao_clear_alarm(void)
+{
+ 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 */
+}
+
+void
+ao_task_info(void)
+{
+ uint8_t i;
+ __xdata struct ao_task *task;
+
+ for (i = 0; i < ao_num_tasks; i++) {
+ task = ao_tasks[i];
+ printf("%12s: wchan %04x\n",
+ task->name,
+ (int16_t) task->wchan);
+ }
+}
+
+void
+ao_start_scheduler(void)
+{
+ ao_cur_task_index = AO_NO_TASK_INDEX;
+ ao_cur_task = NULL;
+ ao_yield();
+}
--- /dev/null
+/*
+ * 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_TELEM_H_
+#define _AO_TELEM_H_
+
+#define AO_TELEMETRY_VERSION 4
+
+/*
+ * Telemetry version 4 and higher format:
+ *
+ * General header fields
+ *
+ * Name Value
+ *
+ * VERSION Telemetry version number (4 or more). Must be first.
+ * c Callsign (string, no spaces allowed)
+ * n Flight unit serial number (integer)
+ * f Flight number (integer)
+ * r Packet RSSI value (integer)
+ * s Flight computer state (string, no spaces allowed)
+ * t Flight computer clock (integer in centiseconds)
+ */
+
+#define AO_TELEM_VERSION "VERSION"
+#define AO_TELEM_CALL "c"
+#define AO_TELEM_SERIAL "n"
+#define AO_TELEM_FLIGHT "f"
+#define AO_TELEM_RSSI "r"
+#define AO_TELEM_STATE "s"
+#define AO_TELEM_TICK "t"
+
+/*
+ * Raw sensor values
+ *
+ * Name Value
+ * r_a Accelerometer reading (integer)
+ * r_b Barometer reading (integer)
+ * r_t Thermometer reading (integer)
+ * r_v Battery reading (integer)
+ * r_d Drogue continuity (integer)
+ * r_m Main continuity (integer)
+ */
+
+#define AO_TELEM_RAW_ACCEL "r_a"
+#define AO_TELEM_RAW_BARO "r_b"
+#define AO_TELEM_RAW_THERMO "r_t"
+#define AO_TELEM_RAW_BATT "r_v"
+#define AO_TELEM_RAW_DROGUE "r_d"
+#define AO_TELEM_RAW_MAIN "r_m"
+
+/*
+ * Sensor calibration values
+ *
+ * Name Value
+ * c_a Ground accelerometer reading (integer)
+ * c_b Ground barometer reading (integer)
+ * c_p Accelerometer reading for +1g
+ * c_m Accelerometer reading for -1g
+ */
+
+#define AO_TELEM_CAL_ACCEL_GROUND "c_a"
+#define AO_TELEM_CAL_BARO_GROUND "c_b"
+#define AO_TELEM_CAL_ACCEL_PLUS "c_p"
+#define AO_TELEM_CAL_ACCEL_MINUS "c_m"
+
+/*
+ * Kalman state values
+ *
+ * Name Value
+ * k_h Height above pad (integer, meters)
+ * k_s Vertical speeed (integer, m/s * 16)
+ * k_a Vertical acceleration (integer, m/s² * 16)
+ */
+
+#define AO_TELEM_KALMAN_HEIGHT "k_h"
+#define AO_TELEM_KALMAN_SPEED "k_s"
+#define AO_TELEM_KALMAN_ACCEL "k_a"
+
+/*
+ * Ad-hoc flight values
+ *
+ * Name Value
+ * a_a Acceleration (integer, sensor units)
+ * a_s Speed (integer, integrated acceleration value)
+ * a_b Barometer reading (integer, sensor units)
+ */
+
+#define AO_TELEM_ADHOC_ACCEL "a_a"
+#define AO_TELEM_ADHOC_SPEED "a_s"
+#define AO_TELEM_ADHOC_BARO "a_b"
+
+/*
+ * GPS values
+ *
+ * Name Value
+ * g GPS state (string):
+ * l locked
+ * u unlocked
+ * e error (missing or broken)
+ * g_n Number of sats used in solution
+ * g_ns Latitude (degrees * 10e7)
+ * g_ew Longitude (degrees * 10e7)
+ * g_a Altitude (integer meters)
+ * g_Y GPS year (integer)
+ * g_M GPS month (integer - 1-12)
+ * g_D GPS day (integer - 1-31)
+ * g_h GPS hour (integer - 0-23)
+ * g_m GPS minute (integer - 0-59)
+ * g_s GPS second (integer - 0-59)
+ * g_v GPS vertical speed (integer, cm/sec)
+ * g_g GPS horizontal speed (integer, cm/sec)
+ * g_c GPS course (integer, 0-359)
+ * g_hd GPS hdop (integer * 10)
+ * g_vd GPS vdop (integer * 10)
+ * g_he GPS h error (integer)
+ * g_ve GPS v error (integer)
+ */
+
+#define AO_TELEM_GPS_STATE "g"
+#define AO_TELEM_GPS_STATE_LOCKED 'l'
+#define AO_TELEM_GPS_STATE_UNLOCKED 'u'
+#define AO_TELEM_GPS_STATE_ERROR 'e'
+#define AO_TELEM_GPS_NUM_SAT "g_n"
+#define AO_TELEM_GPS_LATITUDE "g_ns"
+#define AO_TELEM_GPS_LONGITUDE "g_ew"
+#define AO_TELEM_GPS_ALTITUDE "g_a"
+#define AO_TELEM_GPS_YEAR "g_Y"
+#define AO_TELEM_GPS_MONTH "g_M"
+#define AO_TELEM_GPS_DAY "g_D"
+#define AO_TELEM_GPS_HOUR "g_h"
+#define AO_TELEM_GPS_MINUTE "g_m"
+#define AO_TELEM_GPS_SECOND "g_s"
+#define AO_TELEM_GPS_VERTICAL_SPEED "g_v"
+#define AO_TELEM_GPS_HORIZONTAL_SPEED "g_g"
+#define AO_TELEM_GPS_COURSE "g_c"
+#define AO_TELEM_GPS_HDOP "g_hd"
+#define AO_TELEM_GPS_VDOP "g_vd"
+#define AO_TELEM_GPS_HERROR "g_he"
+#define AO_TELEM_GPS_VERROR "g_ve"
+
+/*
+ * GPS satellite values
+ *
+ * Name Value
+ * s_n Number of satellites reported (integer)
+ * s_v0 Space vehicle ID (integer) for report 0
+ * s_c0 C/N0 number (integer) for report 0
+ * s_v1 Space vehicle ID (integer) for report 1
+ * s_c1 C/N0 number (integer) for report 1
+ * ...
+ */
+
+#define AO_TELEM_SAT_NUM "s_n"
+#define AO_TELEM_SAT_SVID "s_v"
+#define AO_TELEM_SAT_C_N_0 "s_c"
+
+#endif /* _AO_TELEM_H_ */
--- /dev/null
+/*
+ * 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 __pdata uint16_t ao_telemetry_interval;
+static __pdata int8_t ao_telemetry_config_max;
+static __pdata int8_t ao_telemetry_config_cur;
+#if HAS_GPS
+static __pdata int8_t ao_telemetry_loc_cur;
+static __pdata int8_t ao_telemetry_sat_cur;
+#endif
+#if HAS_COMPANION
+static __pdata int8_t ao_telemetry_companion_max;
+static __pdata int8_t ao_telemetry_companion_cur;
+#endif
+static __pdata uint8_t ao_rdf = 0;
+static __pdata uint16_t ao_rdf_time;
+
+#define AO_RDF_INTERVAL_TICKS AO_SEC_TO_TICKS(5)
+#define AO_RDF_LENGTH_MS 500
+
+#if defined(TELEMETRUM_V_0_1) || defined(TELEMETRUM_V_0_2) || defined(TELEMETRUM_V_1_0) || defined(TELEMETRUM_V_1_1)
+#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELEMETRUM
+#endif
+
+#if defined(TELEMINI_V_1_0)
+#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELEMINI
+#endif
+
+#if defined(TELENANO_V_0_1)
+#define AO_TELEMETRY_SENSOR AO_TELEMETRY_SENSOR_TELENANO
+#endif
+
+static __xdata union ao_telemetry_all telemetry;
+
+/* Send sensor packet */
+static void
+ao_send_sensor(void)
+{
+ uint8_t sample;
+ sample = ao_sample_adc;
+
+ telemetry.generic.tick = ao_adc_ring[sample].tick;
+ telemetry.generic.type = AO_TELEMETRY_SENSOR;
+
+ telemetry.sensor.state = ao_flight_state;
+#if HAS_ACCEL
+ telemetry.sensor.accel = ao_adc_ring[sample].accel;
+#else
+ telemetry.sensor.accel = 0;
+#endif
+ telemetry.sensor.pres = ao_adc_ring[sample].pres;
+ telemetry.sensor.temp = ao_adc_ring[sample].temp;
+ telemetry.sensor.v_batt = ao_adc_ring[sample].v_batt;
+#if HAS_IGNITE
+ telemetry.sensor.sense_d = ao_adc_ring[sample].sense_d;
+ telemetry.sensor.sense_m = ao_adc_ring[sample].sense_m;
+#else
+ telemetry.sensor.sense_d = 0;
+ telemetry.sensor.sense_m = 0;
+#endif
+
+ telemetry.sensor.acceleration = ao_accel;
+ telemetry.sensor.speed = ao_speed;
+ telemetry.sensor.height = ao_height;
+
+ telemetry.sensor.ground_pres = ao_ground_pres;
+#if HAS_ACCEL
+ telemetry.sensor.ground_accel = ao_ground_accel;
+ telemetry.sensor.accel_plus_g = ao_config.accel_plus_g;
+ telemetry.sensor.accel_minus_g = ao_config.accel_minus_g;
+#else
+ telemetry.sensor.ground_accel = 0;
+ telemetry.sensor.accel_plus_g = 0;
+ telemetry.sensor.accel_minus_g = 0;
+#endif
+
+ 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)
+{
+ if (--ao_telemetry_config_cur <= 0)
+ {
+ telemetry.generic.type = AO_TELEMETRY_CONFIGURATION;
+ telemetry.configuration.device = AO_idProduct_NUMBER;
+ telemetry.configuration.flight = ao_log_full() ? 0 : ao_flight_number;
+ telemetry.configuration.config_major = AO_CONFIG_MAJOR;
+ telemetry.configuration.config_minor = AO_CONFIG_MINOR;
+ telemetry.configuration.apogee_delay = ao_config.apogee_delay;
+ telemetry.configuration.main_deploy = ao_config.main_deploy;
+ telemetry.configuration.flight_log_max = ao_config.flight_log_max >> 10;
+ memcpy (telemetry.configuration.callsign,
+ ao_config.callsign,
+ AO_MAX_CALLSIGN);
+ memcpy (telemetry.configuration.version,
+ ao_version,
+ AO_MAX_VERSION);
+ ao_radio_send(&telemetry, sizeof (telemetry));
+ ao_telemetry_config_cur = ao_telemetry_config_max;
+ }
+}
+
+#if HAS_GPS
+static void
+ao_send_location(void)
+{
+ if (--ao_telemetry_loc_cur <= 0)
+ {
+ telemetry.generic.type = AO_TELEMETRY_LOCATION;
+ ao_mutex_get(&ao_gps_mutex);
+ memcpy(&telemetry.location.flags,
+ &ao_gps_data.flags,
+ 26);
+ ao_mutex_put(&ao_gps_mutex);
+ ao_radio_send(&telemetry, sizeof (telemetry));
+ ao_telemetry_loc_cur = ao_telemetry_config_max;
+ }
+}
+
+static void
+ao_send_satellite(void)
+{
+ if (--ao_telemetry_sat_cur <= 0)
+ {
+ telemetry.generic.type = AO_TELEMETRY_SATELLITE;
+ ao_mutex_get(&ao_gps_mutex);
+ telemetry.satellite.channels = ao_gps_tracking_data.channels;
+ memcpy(&telemetry.satellite.sats,
+ &ao_gps_tracking_data.sats,
+ AO_MAX_GPS_TRACKING * sizeof (struct ao_telemetry_satellite_info));
+ ao_mutex_put(&ao_gps_mutex);
+ ao_radio_send(&telemetry, sizeof (telemetry));
+ ao_telemetry_sat_cur = ao_telemetry_config_max;
+ }
+}
+#endif
+
+#if HAS_COMPANION
+static void
+ao_send_companion(void)
+{
+ if (--ao_telemetry_companion_cur <= 0) {
+ telemetry.generic.type = AO_TELEMETRY_COMPANION;
+ telemetry.companion.board_id = ao_companion_setup.board_id;
+ telemetry.companion.update_period = ao_companion_setup.update_period;
+ telemetry.companion.channels = ao_companion_setup.channels;
+ ao_mutex_get(&ao_companion_mutex);
+ memcpy(&telemetry.companion.companion_data,
+ ao_companion_data,
+ ao_companion_setup.channels * 2);
+ ao_mutex_put(&ao_companion_mutex);
+ ao_radio_send(&telemetry, sizeof (telemetry));
+ ao_telemetry_companion_cur = ao_telemetry_companion_max;
+ }
+}
+#endif
+
+void
+ao_telemetry(void)
+{
+ uint16_t time;
+ int16_t delay;
+
+ ao_config_get();
+ if (!ao_config.radio_enable)
+ ao_exit();
+ while (!ao_flight_number)
+ ao_sleep(&ao_flight_number);
+
+ telemetry.generic.serial = ao_serial_number;
+ for (;;) {
+ while (ao_telemetry_interval == 0)
+ ao_sleep(&telemetry);
+ time = ao_rdf_time = ao_time();
+ while (ao_telemetry_interval) {
+
+
+#ifdef AO_SEND_ALL_BARO
+ ao_send_baro();
+#endif
+ ao_send_sensor();
+#if HAS_COMPANION
+ if (ao_companion_running)
+ ao_send_companion();
+#endif
+ ao_send_configuration();
+#if HAS_GPS
+ 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_MS_TO_RDF_LEN(AO_RDF_LENGTH_MS));
+ }
+#endif
+ time += ao_telemetry_interval;
+ delay = time - ao_time();
+ if (delay > 0)
+ ao_delay(delay);
+ else
+ time = ao_time();
+ }
+ }
+}
+
+void
+ao_telemetry_set_interval(uint16_t interval)
+{
+ ao_telemetry_interval = interval;
+
+#if HAS_COMPANION
+ if (!ao_companion_setup.update_period)
+ ao_companion_setup.update_period = AO_SEC_TO_TICKS(1);
+ ao_telemetry_companion_max = ao_companion_setup.update_period / interval;
+ ao_telemetry_companion_cur = 1;
+#endif
+
+ ao_telemetry_config_max = AO_SEC_TO_TICKS(1) / interval;
+#if HAS_COMPANION
+ ao_telemetry_config_cur = ao_telemetry_companion_cur;
+ if (ao_telemetry_config_max > ao_telemetry_config_cur)
+ ao_telemetry_config_cur++;
+#else
+ ao_telemetry_config_cur = 1;
+#endif
+
+#if HAS_GPS
+ ao_telemetry_loc_cur = ao_telemetry_config_cur;
+ if (ao_telemetry_config_max > ao_telemetry_loc_cur)
+ ao_telemetry_loc_cur++;
+ ao_telemetry_sat_cur = ao_telemetry_loc_cur;
+ if (ao_telemetry_config_max > ao_telemetry_sat_cur)
+ ao_telemetry_sat_cur++;
+#endif
+ ao_wakeup(&telemetry);
+}
+
+void
+ao_rdf_set(uint8_t rdf)
+{
+ ao_rdf = rdf;
+ if (rdf == 0)
+ ao_radio_rdf_abort();
+ else
+ ao_rdf_time = ao_time();
+}
+
+__xdata struct ao_task ao_telemetry_task;
+
+void
+ao_telemetry_init()
+{
+ ao_add_task(&ao_telemetry_task, ao_telemetry, "telemetry");
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_25lc1024.h"
+
+#define EE_BLOCK_SIZE ((uint16_t) (256))
+#define EE_BLOCK_SHIFT 8
+#define EE_DEVICE_SIZE ((uint32_t) 128 * (uint32_t) 1024)
+
+/* Total bytes of available storage */
+__pdata uint32_t ao_storage_total;
+
+/* Block size - device is erased in these units. At least 256 bytes */
+__pdata uint32_t ao_storage_block;
+
+/* Byte offset of config block. Will be ao_storage_block bytes long */
+__pdata uint32_t ao_storage_config;
+
+/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */
+__pdata uint16_t ao_storage_unit;
+
+/*
+ * Using SPI on USART 0, with P1_2 as the chip select
+ */
+
+#define EE_CS P1_2
+#define EE_CS_INDEX 2
+
+static __xdata uint8_t ao_ee_mutex;
+
+#define ao_ee_delay() do { \
+ _asm nop _endasm; \
+ _asm nop _endasm; \
+ _asm nop _endasm; \
+} while(0)
+
+#define ao_ee_cs_low() ao_spi_get_bit(EE_CS)
+
+#define ao_ee_cs_high() ao_spi_put_bit(EE_CS)
+
+struct ao_ee_instruction {
+ uint8_t instruction;
+ uint8_t address[3];
+} __xdata ao_ee_instruction;
+
+static void
+ao_ee_write_enable(void)
+{
+ ao_ee_cs_low();
+ ao_ee_instruction.instruction = EE_WREN;
+ ao_spi_send(&ao_ee_instruction, 1);
+ ao_ee_cs_high();
+}
+
+static uint8_t
+ao_ee_rdsr(void)
+{
+ ao_ee_cs_low();
+ ao_ee_instruction.instruction = EE_RDSR;
+ ao_spi_send(&ao_ee_instruction, 1);
+ ao_spi_recv(&ao_ee_instruction, 1);
+ ao_ee_cs_high();
+ return ao_ee_instruction.instruction;
+}
+
+static void
+ao_ee_wrsr(uint8_t status)
+{
+ ao_ee_cs_low();
+ ao_ee_instruction.instruction = EE_WRSR;
+ ao_ee_instruction.address[0] = status;
+ ao_spi_send(&ao_ee_instruction, 2);
+ ao_ee_cs_high();
+}
+
+#define EE_BLOCK_NONE 0xffff
+
+static __xdata uint8_t ao_ee_data[EE_BLOCK_SIZE];
+static __pdata uint16_t ao_ee_block = EE_BLOCK_NONE;
+static __pdata uint8_t ao_ee_block_dirty;
+
+/* Write the current block to the EEPROM */
+static void
+ao_ee_write_block(void)
+{
+ uint8_t status;
+
+ status = ao_ee_rdsr();
+ if (status & (EE_STATUS_BP0|EE_STATUS_BP1|EE_STATUS_WPEN)) {
+ status &= ~(EE_STATUS_BP0|EE_STATUS_BP1|EE_STATUS_WPEN);
+ ao_ee_wrsr(status);
+ }
+ ao_ee_write_enable();
+ ao_ee_cs_low();
+ ao_ee_instruction.instruction = EE_WRITE;
+ ao_ee_instruction.address[0] = ao_ee_block >> 8;
+ ao_ee_instruction.address[1] = ao_ee_block;
+ ao_ee_instruction.address[2] = 0;
+ ao_spi_send(&ao_ee_instruction, 4);
+ ao_spi_send(ao_ee_data, EE_BLOCK_SIZE);
+ ao_ee_cs_high();
+ for (;;) {
+ uint8_t status = ao_ee_rdsr();
+ if ((status & EE_STATUS_WIP) == 0)
+ break;
+ }
+}
+
+/* Read the current block from the EEPROM */
+static void
+ao_ee_read_block(void)
+{
+ ao_ee_cs_low();
+ ao_ee_instruction.instruction = EE_READ;
+ ao_ee_instruction.address[0] = ao_ee_block >> 8;
+ ao_ee_instruction.address[1] = ao_ee_block;
+ ao_ee_instruction.address[2] = 0;
+ ao_spi_send(&ao_ee_instruction, 4);
+ ao_spi_recv(ao_ee_data, EE_BLOCK_SIZE);
+ ao_ee_cs_high();
+}
+
+static void
+ao_ee_flush_internal(void)
+{
+ if (ao_ee_block_dirty) {
+ ao_ee_write_block();
+ ao_ee_block_dirty = 0;
+ }
+}
+
+static void
+ao_ee_fill(uint16_t block)
+{
+ if (block != ao_ee_block) {
+ ao_ee_flush_internal();
+ ao_ee_block = block;
+ ao_ee_read_block();
+ }
+}
+
+uint8_t
+ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
+{
+ uint16_t block = (uint16_t) (pos >> EE_BLOCK_SHIFT);
+
+ /* Transfer the data */
+ ao_mutex_get(&ao_ee_mutex); {
+ if (len != EE_BLOCK_SIZE)
+ ao_ee_fill(block);
+ else {
+ ao_ee_flush_internal();
+ ao_ee_block = block;
+ }
+ memcpy(ao_ee_data + (uint16_t) (pos & 0xff), buf, len);
+ ao_ee_block_dirty = 1;
+ } ao_mutex_put(&ao_ee_mutex);
+ return 1;
+}
+
+uint8_t
+ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
+{
+ uint16_t block = (uint16_t) (pos >> EE_BLOCK_SHIFT);
+
+ /* Transfer the data */
+ ao_mutex_get(&ao_ee_mutex); {
+ ao_ee_fill(block);
+ memcpy(buf, ao_ee_data + (uint16_t) (pos & 0xff), len);
+ } ao_mutex_put(&ao_ee_mutex);
+ return 1;
+}
+
+void
+ao_storage_flush(void) __reentrant
+{
+ ao_mutex_get(&ao_ee_mutex); {
+ ao_ee_flush_internal();
+ } ao_mutex_put(&ao_ee_mutex);
+}
+
+uint8_t
+ao_storage_erase(uint32_t pos) __reentrant
+{
+ ao_mutex_get(&ao_ee_mutex); {
+ ao_ee_flush_internal();
+ ao_ee_block = (uint16_t) (pos >> EE_BLOCK_SHIFT);
+ memset(ao_ee_data, 0xff, EE_BLOCK_SIZE);
+ ao_ee_block_dirty = 1;
+ } ao_mutex_put(&ao_ee_mutex);
+ return 1;
+}
+
+static void
+ee_store(void) __reentrant
+{
+}
+
+void
+ao_storage_setup(void)
+{
+ if (ao_storage_total == 0) {
+ ao_storage_total = EE_DEVICE_SIZE;
+ ao_storage_block = EE_BLOCK_SIZE;
+ ao_storage_config = EE_DEVICE_SIZE - EE_BLOCK_SIZE;
+ ao_storage_unit = EE_BLOCK_SIZE;
+ }
+}
+
+void
+ao_storage_device_info(void) __reentrant
+{
+}
+
+/*
+ * To initialize the chip, set up the CS line and
+ * the SPI interface
+ */
+void
+ao_storage_device_init(void)
+{
+ /* set up CS */
+ EE_CS = 1;
+ P1DIR |= (1 << EE_CS_INDEX);
+ P1SEL &= ~(1 << EE_CS_INDEX);
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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.
+ */
+
+/* Defines for the 25LC1024 1Mbit SPI Bus Serial EEPROM */
+
+#ifndef _25LC1024_H_
+#define _25LC1024_H_
+
+#define EE_READ 0x03
+#define EE_WRITE 0x02
+#define EE_WREN 0x06
+#define EE_WRDI 0x04
+#define EE_RDSR 0x05
+#define EE_WRSR 0x01
+#define EE_PE 0x42
+#define EE_SE 0xd8
+#define EE_CE 0xc7
+#define EE_RDID 0xab
+#define EE_DPD 0xb9
+
+#define EE_STATUS_WIP (1 << 0)
+#define EE_STATUS_WEL (1 << 1)
+#define EE_STATUS_BP0 (1 << 2)
+#define EE_STATUS_BP1 (1 << 3)
+#define EE_STATUS_WPEN (1 << 7)
+
+#endif /* _25LC1024_H_ */
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_at45db161d.h"
+
+/* Total bytes of available storage */
+__pdata uint32_t ao_storage_total;
+
+/* Block size - device is erased in these units. At least 256 bytes */
+__pdata uint32_t ao_storage_block;
+
+/* Byte offset of config block. Will be ao_storage_block bytes long */
+__pdata uint32_t ao_storage_config;
+
+/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */
+__pdata uint16_t ao_storage_unit;
+
+#define FLASH_CS P1_1
+#define FLASH_CS_INDEX 1
+
+#define FLASH_BLOCK_SIZE_MAX 512
+
+__xdata uint8_t ao_flash_mutex;
+
+#define ao_flash_delay() do { \
+ _asm nop _endasm; \
+ _asm nop _endasm; \
+ _asm nop _endasm; \
+} while(0)
+
+#define ao_flash_cs_low() ao_spi_get_bit(FLASH_CS)
+
+#define ao_flash_cs_high() ao_spi_put_bit(FLASH_CS)
+
+struct ao_flash_instruction {
+ uint8_t instruction;
+ uint8_t address[3];
+} __xdata ao_flash_instruction;
+
+static void
+ao_flash_set_pagesize_512(void)
+{
+ ao_flash_cs_low();
+ ao_flash_instruction.instruction = FLASH_SET_CONFIG;
+ ao_flash_instruction.address[0] = FLASH_SET_512_BYTE_0;
+ ao_flash_instruction.address[1] = FLASH_SET_512_BYTE_1;
+ ao_flash_instruction.address[2] = FLASH_SET_512_BYTE_2;
+ ao_spi_send(&ao_flash_instruction, 4);
+ ao_flash_cs_high();
+}
+
+
+static uint8_t
+ao_flash_read_status(void)
+{
+ ao_flash_cs_low();
+ ao_flash_instruction.instruction = FLASH_READ_STATUS;
+ ao_spi_send(&ao_flash_instruction, 1);
+ ao_spi_recv(&ao_flash_instruction, 1);
+ ao_flash_cs_high();
+ return ao_flash_instruction.instruction;
+}
+
+#define FLASH_BLOCK_NONE 0xffff
+
+static __xdata uint8_t ao_flash_data[FLASH_BLOCK_SIZE_MAX];
+static __pdata uint16_t ao_flash_block = FLASH_BLOCK_NONE;
+static __pdata uint8_t ao_flash_block_dirty;
+static __pdata uint8_t ao_flash_write_pending;
+static __pdata uint8_t ao_flash_setup_done;
+static __pdata uint8_t ao_flash_block_shift;
+static __pdata uint16_t ao_flash_block_size;
+static __pdata uint16_t ao_flash_block_mask;
+
+void
+ao_storage_setup(void) __reentrant
+{
+ uint8_t status;
+
+ if (ao_flash_setup_done)
+ return;
+
+ ao_mutex_get(&ao_flash_mutex);
+ if (ao_flash_setup_done) {
+ ao_mutex_put(&ao_flash_mutex);
+ return;
+ }
+
+ /* On first use, check to see if the flash chip has
+ * been programmed to use 512 byte pages. If not, do so.
+ * And then, because the flash part must be power cycled
+ * for that change to take effect, panic.
+ */
+ status = ao_flash_read_status();
+
+ if (!(status & FLASH_STATUS_PAGESIZE_512)) {
+ ao_flash_set_pagesize_512();
+ ao_panic(AO_PANIC_FLASH);
+ }
+
+ switch (status & 0x3c) {
+
+ /* AT45DB321D */
+ case 0x34:
+ ao_flash_block_shift = 9;
+ ao_storage_total = ((uint32_t) 4 * (uint32_t) 1024 * (uint32_t) 1024);
+ break;
+
+ /* AT45DB161D */
+ case 0x2c:
+ ao_flash_block_shift = 9;
+ ao_storage_total = ((uint32_t) 2 * (uint32_t) 1024 * (uint32_t) 1024);
+ break;
+
+ /* AT45DB081D */
+ case 0x24:
+ ao_flash_block_shift = 8;
+ ao_storage_total = ((uint32_t) 1024 * (uint32_t) 1024);
+ break;
+
+ /* AT45DB041D */
+ case 0x1c:
+ ao_flash_block_shift = 8;
+ ao_storage_total = ((uint32_t) 512 * (uint32_t) 1024);
+ break;
+
+ /* AT45DB021D */
+ case 0x14:
+ ao_flash_block_shift = 8;
+ ao_storage_total = ((uint32_t) 256 * (uint32_t) 1024);
+ break;
+
+ /* AT45DB011D */
+ case 0x0c:
+ ao_flash_block_shift = 8;
+ ao_storage_total = ((uint32_t) 128 * (uint32_t) 1024);
+ break;
+
+ default:
+ ao_panic(AO_PANIC_FLASH);
+ }
+ ao_flash_block_size = 1 << ao_flash_block_shift;
+ ao_flash_block_mask = ao_flash_block_size - 1;
+
+ ao_storage_block = ao_flash_block_size;
+ ao_storage_config = ao_storage_total - ao_storage_block;
+ ao_storage_unit = ao_flash_block_size;
+
+ ao_flash_setup_done = 1;
+ ao_mutex_put(&ao_flash_mutex);
+}
+
+static void
+ao_flash_wait_write(void)
+{
+ if (ao_flash_write_pending) {
+ for (;;) {
+ uint8_t status = ao_flash_read_status();
+ if ((status & FLASH_STATUS_RDY))
+ break;
+ }
+ ao_flash_write_pending = 0;
+ }
+}
+
+/* Write the current block to the FLASHPROM */
+static void
+ao_flash_write_block(void)
+{
+ ao_flash_wait_write();
+ ao_flash_cs_low();
+ ao_flash_instruction.instruction = FLASH_WRITE;
+
+ /* 13/14 block bits + 9/8 byte bits (always 0) */
+ ao_flash_instruction.address[0] = ao_flash_block >> (16 - ao_flash_block_shift);
+ ao_flash_instruction.address[1] = ao_flash_block << (ao_flash_block_shift - 8);
+ ao_flash_instruction.address[2] = 0;
+ ao_spi_send(&ao_flash_instruction, 4);
+ ao_spi_send(ao_flash_data, ao_storage_block);
+ ao_flash_cs_high();
+ ao_flash_write_pending = 1;
+}
+
+/* Read the current block from the FLASHPROM */
+static void
+ao_flash_read_block(void)
+{
+ ao_flash_wait_write();
+ ao_flash_cs_low();
+ ao_flash_instruction.instruction = FLASH_READ;
+
+ /* 13/14 block bits + 9/8 byte bits (always 0) */
+ ao_flash_instruction.address[0] = ao_flash_block >> (16 - ao_flash_block_shift);
+ ao_flash_instruction.address[1] = ao_flash_block << (ao_flash_block_shift - 8);
+ ao_flash_instruction.address[2] = 0;
+ ao_spi_send(&ao_flash_instruction, 4);
+ ao_spi_recv(ao_flash_data, ao_flash_block_size);
+ ao_flash_cs_high();
+}
+
+static void
+ao_flash_flush_internal(void)
+{
+ if (ao_flash_block_dirty) {
+ ao_flash_write_block();
+ ao_flash_block_dirty = 0;
+ }
+}
+
+static void
+ao_flash_fill(uint16_t block)
+{
+ if (block != ao_flash_block) {
+ ao_flash_flush_internal();
+ ao_flash_block = block;
+ ao_flash_read_block();
+ }
+}
+
+uint8_t
+ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
+{
+ uint16_t block = (uint16_t) (pos >> ao_flash_block_shift);
+
+ /* Transfer the data */
+ ao_mutex_get(&ao_flash_mutex); {
+ if (len != ao_flash_block_size)
+ ao_flash_fill(block);
+ else {
+ ao_flash_flush_internal();
+ ao_flash_block = block;
+ }
+ memcpy(ao_flash_data + (uint16_t) (pos & ao_flash_block_mask),
+ buf,
+ len);
+ ao_flash_block_dirty = 1;
+ } ao_mutex_put(&ao_flash_mutex);
+ return 1;
+}
+
+uint8_t
+ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
+{
+ uint16_t block = (uint16_t) (pos >> ao_flash_block_shift);
+
+ /* Transfer the data */
+ ao_mutex_get(&ao_flash_mutex); {
+ ao_flash_fill(block);
+ memcpy(buf,
+ ao_flash_data + (uint16_t) (pos & ao_flash_block_mask),
+ len);
+ } ao_mutex_put(&ao_flash_mutex);
+ return 1;
+}
+
+void
+ao_storage_flush(void) __reentrant
+{
+ ao_mutex_get(&ao_flash_mutex); {
+ ao_flash_flush_internal();
+ } ao_mutex_put(&ao_flash_mutex);
+}
+
+uint8_t
+ao_storage_erase(uint32_t pos) __reentrant
+{
+ ao_mutex_get(&ao_flash_mutex); {
+ ao_flash_flush_internal();
+ ao_flash_block = (uint16_t) (pos >> ao_flash_block_shift);
+ memset(ao_flash_data, 0xff, ao_flash_block_size);
+ ao_flash_block_dirty = 1;
+ } ao_mutex_put(&ao_flash_mutex);
+ return 1;
+}
+
+void
+ao_storage_device_info(void) __reentrant
+{
+ uint8_t status;
+
+ ao_storage_setup();
+ ao_mutex_get(&ao_flash_mutex); {
+ status = ao_flash_read_status();
+ printf ("Flash status: 0x%02x\n", status);
+ printf ("Flash block shift: %d\n", ao_flash_block_shift);
+ printf ("Flash block size: %d\n", ao_flash_block_size);
+ printf ("Flash block mask: %d\n", ao_flash_block_mask);
+ printf ("Flash device size: %ld\n", ao_storage_total);
+ } ao_mutex_put(&ao_flash_mutex);
+}
+
+/*
+ * To initialize the chip, set up the CS line and
+ * the SPI interface
+ */
+void
+ao_storage_device_init(void)
+{
+ /* set up CS */
+ FLASH_CS = 1;
+ P1DIR |= (1 << FLASH_CS_INDEX);
+ P1SEL &= ~(1 << FLASH_CS_INDEX);
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+/* Defines for the Atmel AT45DB161D 16Mbit SPI Bus DataFlash® */
+
+#ifndef _AT45DB161D_H_
+#define _AT45DB161D_H_
+
+/*
+ * We reserve the last block on the device for
+ * configuration space. Writes and reads in this
+ * area return errors.
+ */
+
+
+#define FLASH_READ 0x03
+#define FLASH_WRITE 0x82
+#define FLASH_PAGE_ERASE 0x81
+#define FLASH_READ_STATUS 0xd7
+#define FLASH_SET_CONFIG 0x3d
+
+#define FLASH_SET_512_BYTE_0 0x2a
+#define FLASH_SET_512_BYTE_1 0x80
+#define FLASH_SET_512_BYTE_2 0xa6
+
+#define FLASH_STATUS_RDY (1 << 7)
+#define FLASH_STATUS_COMP (1 << 6)
+#define FLASH_STATUS_PROTECT (1 << 1)
+#define FLASH_STATUS_PAGESIZE_512 (1 << 0)
+
+#endif /* _AT45DB161D_H_ */
--- /dev/null
+/*
+ * 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"
+
+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];
+
+extern volatile __xdata struct ao_fifo ao_usart1_rx_fifo;
+
+/*
+ * Read a line of data from the serial port, truncating
+ * it after a few characters.
+ */
+
+uint8_t
+ao_btm_get_line(void)
+{
+ uint8_t ao_btm_reply_len = 0;
+ char c;
+
+ 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')
+ goto done;
+ }
+ for (c = 0; c < 10; c++) {
+ ao_delay(AO_MS_TO_TICKS(10));
+ if (!ao_fifo_empty(ao_usart1_rx_fifo))
+ break;
+ }
+ if (c == 10)
+ goto done;
+ }
+done:
+ for (c = ao_btm_reply_len; c < sizeof (ao_btm_reply);)
+ ao_btm_reply[c++] = '\0';
+ return ao_btm_reply_len;
+}
+
+/*
+ * Drain the serial port completely
+ */
+void
+ao_btm_drain()
+{
+ while (ao_btm_get_line())
+ ;
+}
+
+/*
+ * Set the stdio echo for the bluetooth link
+ */
+void
+ao_btm_echo(uint8_t echo)
+{
+ ao_stdios[ao_btm_stdio].echo = echo;
+}
+
+/*
+ * Delay between command charaters; the BT module
+ * can't keep up with 57600 baud
+ */
+
+void
+ao_btm_putchar(char c)
+{
+ ao_btm_log_out_char(c);
+ ao_serial_putchar(c);
+ ao_delay(1);
+}
+
+/*
+ * Wait for the bluetooth device to return
+ * status from the previously executed command
+ */
+uint8_t
+ao_btm_wait_reply(void)
+{
+ for (;;) {
+ ao_btm_get_line();
+ if (!strncmp(ao_btm_reply, "OK", 2))
+ return 1;
+ if (!strncmp(ao_btm_reply, "ERROR", 5))
+ return -1;
+ if (ao_btm_reply[0] == '\0')
+ return 0;
+ }
+}
+
+void
+ao_btm_string(__code char *cmd)
+{
+ char c;
+
+ while (c = *cmd++)
+ ao_btm_putchar(c);
+}
+
+uint8_t
+ao_btm_cmd(__code char *cmd)
+{
+ ao_btm_drain();
+ ao_btm_string(cmd);
+ return ao_btm_wait_reply();
+}
+
+uint8_t
+ao_btm_set_name(void)
+{
+ char sn[8];
+ char *s = sn + 8;
+ char c;
+ int n;
+ ao_btm_string("ATN=TeleBT-");
+ *--s = '\0';
+ *--s = '\r';
+ n = ao_serial_number;
+ do {
+ *--s = '0' + n % 10;
+ } while (n /= 10);
+ while ((c = *s++))
+ ao_btm_putchar(c);
+ return ao_btm_wait_reply();
+}
+
+uint8_t
+ao_btm_try_speed(uint8_t speed)
+{
+ ao_serial_set_speed(speed);
+ ao_btm_drain();
+ (void) ao_btm_cmd("\rATE0\rATQ0\r");
+ if (ao_btm_cmd("AT\r") == 1)
+ return 1;
+ return 0;
+}
+
+/*
+ * A thread to initialize the bluetooth device and
+ * hang around to blink the LED when connected
+ */
+void
+ao_btm(void)
+{
+ /*
+ * Wait for the bluetooth device to boot
+ */
+ ao_delay(AO_SEC_TO_TICKS(3));
+
+ /*
+ * 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
+ * if it is already running at 57600 baud, and if that doesn't work
+ * then tell it to switch to 57600 from 19200 baud.
+ */
+ while (!ao_btm_try_speed(AO_SERIAL_SPEED_57600)) {
+ ao_delay(AO_SEC_TO_TICKS(1));
+ if (ao_btm_try_speed(AO_SERIAL_SPEED_19200))
+ ao_btm_cmd("ATL4\r");
+ ao_delay(AO_SEC_TO_TICKS(1));
+ }
+
+ /* Disable echo */
+ ao_btm_cmd("ATE0\r");
+
+ /* Enable flow control */
+ ao_btm_cmd("ATC1\r");
+
+ /* Set the reported name to something we can find on the host */
+ ao_btm_set_name();
+
+ /* Turn off status reporting */
+ ao_btm_cmd("ATQ1\r");
+
+ ao_btm_stdio = ao_add_stdio(ao_serial_pollchar,
+ ao_serial_putchar,
+ NULL);
+ ao_btm_echo(0);
+
+ for (;;) {
+ while (!ao_btm_connected)
+ ao_sleep(&ao_btm_connected);
+ while (ao_btm_connected) {
+ ao_led_for(AO_LED_GREEN, AO_MS_TO_TICKS(20));
+ ao_delay(AO_SEC_TO_TICKS(3));
+ }
+ }
+}
+
+__xdata struct ao_task ao_btm_task;
+
+#if BT_LINK_ON_P2
+#define BT_PICTL_ICON PICTL_P2ICON
+#define BT_PIFG P2IFG
+#define BT_PDIR P2DIR
+#define BT_PINP P2INP
+#define BT_IEN2_PIE IEN2_P2IE
+#endif
+#if BT_LINK_ON_P1
+#define BT_PICTL_ICON PICTL_P1ICON
+#define BT_PIFG P1IFG
+#define BT_PDIR P1DIR
+#define BT_PINP P1INP
+#define BT_IEN2_PIE IEN2_P1IE
+#endif
+
+void
+ao_btm_check_link() __critical
+{
+ /* Check the pin and configure the interrupt detector to wait for the
+ * pin to flip the other way
+ */
+ if (BT_LINK_PIN) {
+ ao_btm_connected = 0;
+ PICTL |= BT_PICTL_ICON;
+ } else {
+ ao_btm_connected = 1;
+ PICTL &= ~BT_PICTL_ICON;
+ }
+}
+
+void
+ao_btm_isr(void)
+#if BT_LINK_ON_P1
+ __interrupt 15
+#endif
+{
+#if BT_LINK_ON_P1
+ P1IF = 0;
+#endif
+ if (BT_PIFG & (1 << BT_LINK_PIN_INDEX)) {
+ ao_btm_check_link();
+ ao_wakeup(&ao_btm_connected);
+ }
+ BT_PIFG = 0;
+}
+
+void
+ao_btm_init (void)
+{
+ ao_serial_init();
+ ao_serial_set_speed(AO_SERIAL_SPEED_19200);
+
+#if BT_LINK_ON_P1
+ /*
+ * Configure ser reset line
+ */
+
+ P1_6 = 0;
+ P1DIR |= (1 << 6);
+#endif
+
+ /*
+ * Configure link status line
+ */
+
+ /* Set pin to input */
+ BT_PDIR &= ~(1 << BT_LINK_PIN_INDEX);
+
+ /* Set pin to tri-state */
+ BT_PINP |= (1 << BT_LINK_PIN_INDEX);
+
+ /* Enable interrupts */
+ IEN2 |= BT_IEN2_PIE;
+
+ /* Check current pin state */
+ ao_btm_check_link();
+
+#if BT_LINK_ON_P2
+ /* Eable the pin interrupt */
+ PICTL |= PICTL_P2IEN;
+#endif
+#if BT_LINK_ON_P1
+ /* Enable pin interrupt */
+ P1IEN |= (1 << BT_LINK_PIN_INDEX);
+#endif
+
+ ao_add_task(&ao_btm_task, ao_btm, "bt");
+ ao_btm_log_init();
+}
--- /dev/null
+/*
+ * 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_spi_slow() (U0GCR = (UxGCR_CPOL_NEGATIVE | \
+ UxGCR_CPHA_FIRST_EDGE | \
+ UxGCR_ORDER_MSB | \
+ (13 << UxGCR_BAUD_E_SHIFT)))
+
+#define ao_spi_fast() (U0GCR = (UxGCR_CPOL_NEGATIVE | \
+ UxGCR_CPHA_FIRST_EDGE | \
+ UxGCR_ORDER_MSB | \
+ (17 << UxGCR_BAUD_E_SHIFT)))
+
+#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)
+
+__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];
+__pdata uint8_t ao_companion_running;
+__xdata uint8_t ao_companion_mutex;
+
+static void
+ao_companion_send_command(uint8_t command)
+{
+ ao_companion_command.command = command;
+ ao_companion_command.flight_state = ao_flight_state;
+ ao_companion_command.tick = ao_time();
+ ao_companion_command.serial = ao_serial_number;
+ ao_companion_command.flight = ao_flight_number;
+ ao_spi_send(&ao_companion_command, sizeof (ao_companion_command));
+}
+
+static uint8_t
+ao_companion_get_setup(void)
+{
+ COMPANION_SELECT();
+ ao_companion_send_command(AO_COMPANION_SETUP);
+ ao_spi_recv(&ao_companion_setup, sizeof (ao_companion_setup));
+ COMPANION_DESELECT();
+ return (ao_companion_setup.board_id ==
+ ~ao_companion_setup.board_id_inverse);
+}
+
+static void
+ao_companion_get_data(void)
+{
+ COMPANION_SELECT();
+ ao_companion_send_command(AO_COMPANION_FETCH);
+ ao_mutex_get(&ao_companion_mutex);
+ ao_spi_recv(&ao_companion_data, ao_companion_setup.channels * 2);
+ ao_mutex_put(&ao_companion_mutex);
+ COMPANION_DESELECT();
+}
+
+static void
+ao_companion_notify(void)
+{
+ COMPANION_SELECT();
+ ao_companion_send_command(AO_COMPANION_NOTIFY);
+ COMPANION_DESELECT();
+}
+
+void
+ao_companion(void)
+{
+ uint8_t i;
+ while (!ao_flight_number)
+ ao_sleep(&ao_flight_number);
+ for (i = 0; i < 10; i++) {
+ ao_delay(AO_SEC_TO_TICKS(1));
+ if ((ao_companion_running = ao_companion_get_setup()))
+ break;
+ }
+ while (ao_companion_running) {
+ ao_alarm(ao_companion_setup.update_period);
+ if (ao_sleep(DATA_TO_XDATA(&ao_flight_state)))
+ ao_companion_get_data();
+ else
+ ao_companion_notify();
+ }
+ ao_exit();
+}
+
+void
+ao_companion_status(void) __reentrant
+{
+ uint8_t i;
+ printf("Companion running: %d\n", ao_companion_running);
+ printf("device: %d\n", ao_companion_setup.board_id);
+ printf("update period: %d\n", ao_companion_setup.update_period);
+ printf("channels: %d\n", ao_companion_setup.channels);
+ printf("data:");
+ for(i = 0; i < ao_companion_setup.channels; i++)
+ printf(" %5u", ao_companion_data[i]);
+ printf("\n");
+}
+
+__code struct ao_cmds ao_companion_cmds[] = {
+ { ao_companion_status, "L\0Companion link status" },
+ { 0, NULL },
+};
+
+static __xdata struct ao_task ao_companion_task;
+
+void
+ao_companion_init(void)
+{
+ COMPANION_CS_PORT |= COMPANION_CS_MASK; /* raise all CS pins */
+ COMPANION_CS_DIR |= COMPANION_CS_MASK; /* set CS pins as outputs */
+ COMPANION_CS_SEL &= ~COMPANION_CS_MASK; /* set CS pins as GPIO */
+
+ ao_cmd_register(&ao_companion_cmds[0]);
+ ao_add_task(&ao_companion_task, ao_companion, "companion");
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_GPS_TEST
+#include "ao.h"
+#endif
+
+__xdata uint8_t ao_gps_mutex;
+__pdata uint16_t ao_gps_tick;
+__xdata struct ao_telemetry_location ao_gps_data;
+__xdata struct ao_telemetry_satellite ao_gps_tracking_data;
+
+static const char ao_gps_set_nmea[] = "\r\n$PSRF100,0,57600,8,1,0*37\r\n";
+
+const char ao_gps_config[] = {
+
+ 0xa0, 0xa2, 0x00, 0x0e, /* length: 14 bytes */
+ 136, /* mode control */
+ 0, 0, /* reserved */
+ 0, /* degraded mode (allow 1-SV navigation) */
+ 0, 0, /* reserved */
+ 0, 0, /* user specified altitude */
+ 2, /* alt hold mode (disabled, require 3d fixes) */
+ 0, /* alt hold source (use last computed altitude) */
+ 0, /* reserved */
+ 10, /* Degraded time out (10 sec) */
+ 10, /* Dead Reckoning time out (10 sec) */
+ 0, /* Track smoothing (disabled) */
+ 0x00, 0x8e, 0xb0, 0xb3,
+
+ 0xa0, 0xa2, 0x00, 0x08, /* length: 8 bytes */
+ 166, /* Set message rate */
+ 2, /* enable/disable all messages */
+ 0, /* message id (ignored) */
+ 0, /* update rate (0 = disable) */
+ 0, 0, 0, 0, /* reserved */
+ 0x00, 0xa8, 0xb0, 0xb3,
+
+ 0xa0, 0xa2, 0x00, 0x02, /* length: 2 bytes */
+ 143, /* static navigation */
+ 0, /* disable */
+ 0x00, 0x8f, 0xb0, 0xb3,
+};
+
+#define NAV_TYPE_GPS_FIX_TYPE_MASK (7 << 0)
+#define NAV_TYPE_NO_FIX (0 << 0)
+#define NAV_TYPE_SV_KF (1 << 0)
+#define NAV_TYPE_2_SV_KF (2 << 0)
+#define NAV_TYPE_3_SV_KF (3 << 0)
+#define NAV_TYPE_4_SV_KF (4 << 0)
+#define NAV_TYPE_2D_LEAST_SQUARES (5 << 0)
+#define NAV_TYPE_3D_LEAST_SQUARES (6 << 0)
+#define NAV_TYPE_DR (7 << 0)
+#define NAV_TYPE_TRICKLE_POWER (1 << 3)
+#define NAV_TYPE_ALTITUDE_HOLD_MASK (3 << 4)
+#define NAV_TYPE_ALTITUDE_HOLD_NONE (0 << 4)
+#define NAV_TYPE_ALTITUDE_HOLD_KF (1 << 4)
+#define NAV_TYPE_ALTITUDE_HOLD_USER (2 << 4)
+#define NAV_TYPE_ALTITUDE_HOLD_ALWAYS (3 << 4)
+#define NAV_TYPE_DOP_LIMIT_EXCEEDED (1 << 6)
+#define NAV_TYPE_DGPS_APPLIED (1 << 7)
+#define NAV_TYPE_SENSOR_DR (1 << 8)
+#define NAV_TYPE_OVERDETERMINED (1 << 9)
+#define NAV_TYPE_DR_TIMEOUT_EXCEEDED (1 << 10)
+#define NAV_TYPE_FIX_MI_EDIT (1 << 11)
+#define NAV_TYPE_INVALID_VELOCITY (1 << 12)
+#define NAV_TYPE_ALTITUDE_HOLD_DISABLED (1 << 13)
+#define NAV_TYPE_DR_ERROR_STATUS_MASK (3 << 14)
+#define NAV_TYPE_DR_ERROR_STATUS_GPS_ONLY (0 << 14)
+#define NAV_TYPE_DR_ERROR_STATUS_DR_FROM_GPS (1 << 14)
+#define NAV_TYPE_DR_ERROR_STATUS_DR_SENSOR_ERROR (2 << 14)
+#define NAV_TYPE_DR_ERROR_STATUS_DR_IN_TEST (3 << 14)
+
+struct sirf_geodetic_nav_data {
+ uint16_t nav_type;
+ uint16_t utc_year;
+ uint8_t utc_month;
+ uint8_t utc_day;
+ uint8_t utc_hour;
+ uint8_t utc_minute;
+ uint16_t utc_second;
+ int32_t lat;
+ int32_t lon;
+ int32_t alt_msl;
+ uint16_t ground_speed;
+ uint16_t course;
+ int16_t climb_rate;
+ uint32_t h_error;
+ uint32_t v_error;
+ uint8_t num_sv;
+ uint8_t hdop;
+};
+
+static __xdata struct sirf_geodetic_nav_data ao_sirf_data;
+
+struct sirf_measured_sat_data {
+ uint8_t svid;
+ uint8_t c_n_1;
+};
+
+struct sirf_measured_tracker_data {
+ int16_t gps_week;
+ uint32_t gps_tow;
+ uint8_t channels;
+ struct sirf_measured_sat_data sats[12];
+};
+
+static __xdata struct sirf_measured_tracker_data ao_sirf_tracker_data;
+
+static __pdata uint16_t ao_sirf_cksum;
+static __pdata uint16_t ao_sirf_len;
+
+#define ao_sirf_byte() ((uint8_t) ao_serial_getchar())
+
+static uint8_t data_byte(void)
+{
+ uint8_t c = ao_sirf_byte();
+ --ao_sirf_len;
+ ao_sirf_cksum += c;
+ return c;
+}
+
+static char __xdata *sirf_target;
+
+static void sirf_u16(uint8_t offset)
+{
+ uint16_t __xdata *ptr = (uint16_t __xdata *) (sirf_target + offset);
+ uint16_t val;
+
+ val = data_byte() << 8;
+ val |= data_byte ();
+ *ptr = val;
+}
+
+static void sirf_u8(uint8_t offset)
+{
+ uint8_t __xdata *ptr = (uint8_t __xdata *) (sirf_target + offset);
+ uint8_t val;
+
+ val = data_byte ();
+ *ptr = val;
+}
+
+static void sirf_u32(uint8_t offset) __reentrant
+{
+ uint32_t __xdata *ptr = (uint32_t __xdata *) (sirf_target + offset);
+ uint32_t val;
+
+ val = ((uint32_t) data_byte ()) << 24;
+ val |= ((uint32_t) data_byte ()) << 16;
+ val |= ((uint32_t) data_byte ()) << 8;
+ val |= ((uint32_t) data_byte ());
+ *ptr = val;
+}
+
+static void sirf_discard(uint8_t len)
+{
+ while (len--)
+ data_byte();
+}
+
+#define SIRF_END 0
+#define SIRF_DISCARD 1
+#define SIRF_U8 2
+#define SIRF_U16 3
+#define SIRF_U32 4
+#define SIRF_U8X10 5
+
+struct sirf_packet_parse {
+ uint8_t type;
+ uint8_t offset;
+};
+
+static void
+ao_sirf_parse(void __xdata *target, const struct sirf_packet_parse *parse) __reentrant
+{
+ uint8_t i, offset, j;
+
+ sirf_target = target;
+ for (i = 0; ; i++) {
+ offset = parse[i].offset;
+ switch (parse[i].type) {
+ case SIRF_END:
+ return;
+ case SIRF_DISCARD:
+ sirf_discard(offset);
+ break;
+ case SIRF_U8:
+ sirf_u8(offset);
+ break;
+ case SIRF_U16:
+ sirf_u16(offset);
+ break;
+ case SIRF_U32:
+ sirf_u32(offset);
+ break;
+ case SIRF_U8X10:
+ for (j = 10; j--;)
+ sirf_u8(offset++);
+ break;
+ }
+ }
+}
+
+static const struct sirf_packet_parse geodetic_nav_data_packet[] = {
+ { SIRF_DISCARD, 2 }, /* 1 nav valid */
+ { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, nav_type) }, /* 3 */
+ { SIRF_DISCARD, 6 }, /* 5 week number, time of week */
+ { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, utc_year) }, /* 11 */
+ { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_month) }, /* 13 */
+ { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_day) }, /* 14 */
+ { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_hour) }, /* 15 */
+ { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, utc_minute) }, /* 16 */
+ { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, utc_second) }, /* 17 */
+ { SIRF_DISCARD, 4 }, /* satellite id list */ /* 19 */
+ { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, lat) }, /* 23 */
+ { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, lon) }, /* 27 */
+ { SIRF_DISCARD, 4 }, /* altitude from ellipsoid */ /* 31 */
+ { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, alt_msl) }, /* 35 */
+ { SIRF_DISCARD, 1 }, /* map datum */ /* 39 */
+ { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, ground_speed) }, /* 40 */
+ { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, course) }, /* 42 */
+ { SIRF_DISCARD, 2 }, /* magnetic variation */ /* 44 */
+ { SIRF_U16, offsetof(struct sirf_geodetic_nav_data, climb_rate) }, /* 46 */
+ { SIRF_DISCARD, 2 }, /* turn rate */ /* 48 */
+ { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, h_error) }, /* 50 */
+ { SIRF_U32, offsetof(struct sirf_geodetic_nav_data, v_error) }, /* 54 */
+ { SIRF_DISCARD, 30 }, /* time error, h_vel error, clock_bias,
+ clock bias error, clock drift,
+ clock drift error, distance,
+ distance error, heading error */ /* 58 */
+ { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, num_sv) }, /* 88 */
+ { SIRF_U8, offsetof(struct sirf_geodetic_nav_data, hdop) }, /* 89 */
+ { SIRF_DISCARD, 1 }, /* additional mode info */ /* 90 */
+ { SIRF_END, 0 }, /* 91 */
+};
+
+static void
+ao_sirf_parse_41(void) __reentrant
+{
+ ao_sirf_parse(&ao_sirf_data, geodetic_nav_data_packet);
+}
+
+static const struct sirf_packet_parse measured_tracker_data_packet[] = {
+ { SIRF_U16, offsetof (struct sirf_measured_tracker_data, gps_week) }, /* 1 week */
+ { SIRF_U32, offsetof (struct sirf_measured_tracker_data, gps_tow) }, /* 3 time of week */
+ { SIRF_U8, offsetof (struct sirf_measured_tracker_data, channels) }, /* 7 channels */
+ { SIRF_END, 0 },
+};
+
+static const struct sirf_packet_parse measured_sat_data_packet[] = {
+ { SIRF_U8, offsetof (struct sirf_measured_sat_data, svid) }, /* 0 SV id */
+ { SIRF_DISCARD, 4 }, /* 1 azimuth, 2 elevation, 3 state */
+ { SIRF_U8, offsetof (struct sirf_measured_sat_data, c_n_1) }, /* C/N0 1 */
+ { SIRF_DISCARD, 9 }, /* C/N0 2-10 */
+ { SIRF_END, 0 },
+};
+
+static void
+ao_sirf_parse_4(void) __reentrant
+{
+ uint8_t i;
+ ao_sirf_parse(&ao_sirf_tracker_data, measured_tracker_data_packet);
+ for (i = 0; i < 12; i++)
+ ao_sirf_parse(&ao_sirf_tracker_data.sats[i], measured_sat_data_packet);
+}
+
+static void
+ao_gps_setup(void) __reentrant
+{
+ uint8_t i, k;
+ ao_serial_set_speed(AO_SERIAL_SPEED_4800);
+ for (i = 0; i < 64; i++)
+ ao_serial_putchar(0x00);
+ for (k = 0; k < 3; k++)
+ for (i = 0; i < sizeof (ao_gps_set_nmea); i++)
+ ao_serial_putchar(ao_gps_set_nmea[i]);
+ ao_serial_set_speed(AO_SERIAL_SPEED_57600);
+ for (i = 0; i < 64; i++)
+ ao_serial_putchar(0x00);
+}
+
+static const char ao_gps_set_message_rate[] = {
+ 0xa0, 0xa2, 0x00, 0x08,
+ 166,
+ 0,
+};
+
+void
+ao_sirf_set_message_rate(uint8_t msg, uint8_t rate) __reentrant
+{
+ uint16_t cksum = 0x00a6;
+ uint8_t i;
+
+ for (i = 0; i < sizeof (ao_gps_set_message_rate); i++)
+ ao_serial_putchar(ao_gps_set_message_rate[i]);
+ ao_serial_putchar(msg);
+ ao_serial_putchar(rate);
+ cksum = 0xa6 + msg + rate;
+ for (i = 0; i < 4; i++)
+ ao_serial_putchar(0);
+ ao_serial_putchar((cksum >> 8) & 0x7f);
+ ao_serial_putchar(cksum & 0xff);
+ ao_serial_putchar(0xb0);
+ ao_serial_putchar(0xb3);
+}
+
+static const uint8_t sirf_disable[] = {
+ 2,
+ 9,
+ 10,
+ 27,
+ 50,
+ 52,
+};
+
+void
+ao_gps(void) __reentrant
+{
+ uint8_t i, k;
+ uint16_t cksum;
+
+ ao_gps_setup();
+ for (k = 0; k < 5; k++)
+ {
+ for (i = 0; i < sizeof (ao_gps_config); i++)
+ ao_serial_putchar(ao_gps_config[i]);
+ for (i = 0; i < sizeof (sirf_disable); i++)
+ ao_sirf_set_message_rate(sirf_disable[i], 0);
+ ao_sirf_set_message_rate(41, 1);
+ ao_sirf_set_message_rate(4, 1);
+ }
+ for (;;) {
+ /* Locate the begining of the next record */
+ while (ao_sirf_byte() != (uint8_t) 0xa0)
+ ;
+ if (ao_sirf_byte() != (uint8_t) 0xa2)
+ continue;
+
+ /* Length */
+ ao_sirf_len = ao_sirf_byte() << 8;
+ ao_sirf_len |= ao_sirf_byte();
+ if (ao_sirf_len > 1023)
+ continue;
+
+ ao_sirf_cksum = 0;
+
+ /* message ID */
+ i = data_byte (); /* 0 */
+
+ switch (i) {
+ case 41:
+ if (ao_sirf_len < 90)
+ break;
+ ao_sirf_parse_41();
+ break;
+ case 4:
+ if (ao_sirf_len < 187)
+ break;
+ ao_sirf_parse_4();
+ break;
+ }
+ if (ao_sirf_len != 0)
+ continue;
+
+ /* verify checksum and end sequence */
+ ao_sirf_cksum &= 0x7fff;
+ cksum = ao_sirf_byte() << 8;
+ cksum |= ao_sirf_byte();
+ if (ao_sirf_cksum != cksum)
+ continue;
+ if (ao_sirf_byte() != (uint8_t) 0xb0)
+ continue;
+ if (ao_sirf_byte() != (uint8_t) 0xb3)
+ continue;
+
+ switch (i) {
+ case 41:
+ ao_mutex_get(&ao_gps_mutex);
+ ao_gps_tick = ao_time();
+ ao_gps_data.hour = ao_sirf_data.utc_hour;
+ ao_gps_data.minute = ao_sirf_data.utc_minute;
+ ao_gps_data.second = ao_sirf_data.utc_second / 1000;
+ ao_gps_data.flags = ((ao_sirf_data.num_sv << AO_GPS_NUM_SAT_SHIFT) & AO_GPS_NUM_SAT_MASK) | AO_GPS_RUNNING;
+ if ((ao_sirf_data.nav_type & NAV_TYPE_GPS_FIX_TYPE_MASK) >= NAV_TYPE_4_SV_KF)
+ ao_gps_data.flags |= AO_GPS_VALID;
+ ao_gps_data.latitude = ao_sirf_data.lat;
+ ao_gps_data.longitude = ao_sirf_data.lon;
+ ao_gps_data.altitude = ao_sirf_data.alt_msl / 100;
+ ao_gps_data.ground_speed = ao_sirf_data.ground_speed;
+ ao_gps_data.course = ao_sirf_data.course / 200;
+ ao_gps_data.hdop = ao_sirf_data.hdop;
+ ao_gps_data.climb_rate = ao_sirf_data.climb_rate;
+ ao_gps_data.flags |= AO_GPS_COURSE_VALID;
+#if 0
+ if (ao_sirf_data.h_error > 6553500)
+ ao_gps_data.h_error = 65535;
+ else
+ ao_gps_data.h_error = ao_sirf_data.h_error / 100;
+ if (ao_sirf_data.v_error > 6553500)
+ ao_gps_data.v_error = 65535;
+ else
+ ao_gps_data.v_error = ao_sirf_data.v_error / 100;
+#endif
+ ao_mutex_put(&ao_gps_mutex);
+ ao_wakeup(&ao_gps_data);
+ break;
+ case 4:
+ ao_mutex_get(&ao_gps_mutex);
+ ao_gps_tracking_data.channels = ao_sirf_tracker_data.channels;
+ for (i = 0; i < 12; i++) {
+ ao_gps_tracking_data.sats[i].svid = ao_sirf_tracker_data.sats[i].svid;
+ ao_gps_tracking_data.sats[i].c_n_1 = ao_sirf_tracker_data.sats[i].c_n_1;
+ }
+ ao_mutex_put(&ao_gps_mutex);
+ ao_wakeup(&ao_gps_tracking_data);
+ break;
+ }
+ }
+}
+
+__xdata struct ao_task ao_gps_task;
+
+void
+ao_gps_init(void)
+{
+ ao_add_task(&ao_gps_task, ao_gps, "gps");
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_GPS_TEST
+#include "ao.h"
+#endif
+
+#define AO_GPS_LEADER 2
+
+static __code char ao_gps_header[] = "GP";
+
+__xdata uint8_t ao_gps_mutex;
+static __data char ao_gps_char;
+static __pdata uint8_t ao_gps_cksum;
+static __pdata uint8_t ao_gps_error;
+
+__pdata uint16_t ao_gps_tick;
+__xdata struct ao_telemetry_location ao_gps_data;
+__xdata struct ao_telemetry_satellite ao_gps_tracking_data;
+
+static __pdata uint16_t ao_gps_next_tick;
+static __xdata struct ao_telemetry_location ao_gps_next;
+static __pdata uint8_t ao_gps_date_flags;
+static __xdata struct ao_telemetry_satellite ao_gps_tracking_next;
+
+#define STQ_S 0xa0, 0xa1
+#define STQ_E 0x0d, 0x0a
+#define SKYTRAQ_MSG_2(id,a,b) \
+ STQ_S, 0, 3, id, a,b, (id^a^b), STQ_E
+#define SKYTRAQ_MSG_3(id,a,b,c) \
+ STQ_S, 0, 4, id, a,b,c, (id^a^b^c), STQ_E
+#define SKYTRAQ_MSG_8(id,a,b,c,d,e,f,g,h) \
+ STQ_S, 0, 9, id, a,b,c,d,e,f,g,h, (id^a^b^c^d^e^f^g^h), STQ_E
+#define SKYTRAQ_MSG_14(id,a,b,c,d,e,f,g,h,i,j,k,l,m,n) \
+ STQ_S, 0,15, id, a,b,c,d,e,f,g,h,i,j,k,l,m,n, \
+ (id^a^b^c^d^e^f^g^h^i^j^k^l^m^n), STQ_E
+
+static __code uint8_t ao_gps_config[] = {
+ SKYTRAQ_MSG_8(0x08, 1, 1, 1, 1, 1, 1, 1, 0), /* configure nmea */
+ /* gga interval */
+ /* gsa interval */
+ /* gsv interval */
+ /* gll interval */
+ /* rmc interval */
+ /* vtg interval */
+ /* zda interval */
+ /* attributes (0 = update to sram, 1 = update flash too) */
+
+ SKYTRAQ_MSG_2(0x3c, 0x00, 0x00), /* configure navigation mode */
+ /* 0 = car, 1 = pedestrian */
+ /* 0 = update to sram, 1 = update sram + flash */
+};
+
+static void
+ao_gps_lexchar(void)
+{
+ if (ao_gps_error)
+ ao_gps_char = '\n';
+ else
+ ao_gps_char = ao_serial_getchar();
+ ao_gps_cksum ^= ao_gps_char;
+}
+
+void
+ao_gps_skip_field(void)
+{
+ while (ao_gps_char != ',' && ao_gps_char != '*' && ao_gps_char != '\n')
+ ao_gps_lexchar();
+}
+
+void
+ao_gps_skip_sep(void)
+{
+ if (ao_gps_char == ',' || ao_gps_char == '.' || ao_gps_char == '*')
+ ao_gps_lexchar();
+}
+
+__pdata static uint8_t ao_gps_num_width;
+
+static int16_t
+ao_gps_decimal(uint8_t max_width)
+{
+ int16_t v;
+ __pdata uint8_t neg = 0;
+
+ ao_gps_skip_sep();
+ if (ao_gps_char == '-') {
+ neg = 1;
+ ao_gps_lexchar();
+ }
+ v = 0;
+ ao_gps_num_width = 0;
+ while (ao_gps_num_width < max_width) {
+ if (ao_gps_char < '0' || '9' < ao_gps_char)
+ break;
+ v = v * (int16_t) 10 + ao_gps_char - '0';
+ ao_gps_num_width++;
+ ao_gps_lexchar();
+ }
+ if (neg)
+ v = -v;
+ return v;
+}
+
+static uint8_t
+ao_gps_hex(uint8_t max_width)
+{
+ uint8_t v, d;
+
+ ao_gps_skip_sep();
+ v = 0;
+ ao_gps_num_width = 0;
+ while (ao_gps_num_width < max_width) {
+ if ('0' <= ao_gps_char && ao_gps_char <= '9')
+ d = ao_gps_char - '0';
+ else if ('A' <= ao_gps_char && ao_gps_char <= 'F')
+ d = ao_gps_char - 'A' + 10;
+ else if ('a' <= ao_gps_char && ao_gps_char <= 'f')
+ d = ao_gps_char - 'a' + 10;
+ else
+ break;
+ v = (v << 4) | d;
+ ao_gps_num_width++;
+ ao_gps_lexchar();
+ }
+ return v;
+}
+
+static int32_t
+ao_gps_parse_pos(uint8_t deg_width) __reentrant
+{
+ int32_t d;
+ int32_t m;
+ int32_t f;
+
+ d = ao_gps_decimal(deg_width);
+ m = ao_gps_decimal(2);
+ if (ao_gps_char == '.') {
+ f = ao_gps_decimal(4);
+ while (ao_gps_num_width < 4) {
+ f *= 10;
+ ao_gps_num_width++;
+ }
+ } else {
+ f = 0;
+ if (ao_gps_char != ',')
+ ao_gps_error = 1;
+ }
+ d = d * 10000000l;
+ m = m * 10000l + f;
+ d = d + m * 50 / 3;
+ return d;
+}
+
+static uint8_t
+ao_gps_parse_flag(char no_c, char yes_c) __reentrant
+{
+ uint8_t ret = 0;
+ ao_gps_skip_sep();
+ if (ao_gps_char == yes_c)
+ ret = 1;
+ else if (ao_gps_char == no_c)
+ ret = 0;
+ else
+ ao_gps_error = 1;
+ ao_gps_lexchar();
+ return ret;
+}
+
+static void
+ao_nmea_gga()
+{
+ uint8_t i;
+
+ /* Now read the data into the gps data record
+ *
+ * $GPGGA,025149.000,4528.1723,N,12244.2480,W,1,05,2.0,103.5,M,-19.5,M,,0000*66
+ *
+ * Essential fix data
+ *
+ * 025149.000 time (02:51:49.000 GMT)
+ * 4528.1723,N Latitude 45°28.1723' N
+ * 12244.2480,W Longitude 122°44.2480' W
+ * 1 Fix quality:
+ * 0 = invalid
+ * 1 = GPS fix (SPS)
+ * 2 = DGPS fix
+ * 3 = PPS fix
+ * 4 = Real Time Kinematic
+ * 5 = Float RTK
+ * 6 = estimated (dead reckoning)
+ * 7 = Manual input mode
+ * 8 = Simulation mode
+ * 05 Number of satellites (5)
+ * 2.0 Horizontal dilution
+ * 103.5,M Altitude, 103.5M above msl
+ * -19.5,M Height of geoid above WGS84 ellipsoid
+ * ? time in seconds since last DGPS update
+ * 0000 DGPS station ID
+ * *66 checksum
+ */
+
+ ao_gps_next_tick = ao_time();
+ ao_gps_next.flags = AO_GPS_RUNNING | ao_gps_date_flags;
+ ao_gps_next.hour = ao_gps_decimal(2);
+ ao_gps_next.minute = ao_gps_decimal(2);
+ ao_gps_next.second = ao_gps_decimal(2);
+ ao_gps_skip_field(); /* skip seconds fraction */
+
+ ao_gps_next.latitude = ao_gps_parse_pos(2);
+ if (ao_gps_parse_flag('N', 'S'))
+ ao_gps_next.latitude = -ao_gps_next.latitude;
+ ao_gps_next.longitude = ao_gps_parse_pos(3);
+ if (ao_gps_parse_flag('E', 'W'))
+ ao_gps_next.longitude = -ao_gps_next.longitude;
+
+ i = ao_gps_decimal(0xff);
+ if (i == 1)
+ ao_gps_next.flags |= AO_GPS_VALID;
+
+ i = ao_gps_decimal(0xff) << AO_GPS_NUM_SAT_SHIFT;
+ if (i > AO_GPS_NUM_SAT_MASK)
+ i = AO_GPS_NUM_SAT_MASK;
+ ao_gps_next.flags |= i;
+
+ ao_gps_lexchar();
+ i = ao_gps_decimal(0xff);
+ if (i <= 50) {
+ i = (uint8_t) 5 * i;
+ if (ao_gps_char == '.')
+ i = (i + ((uint8_t) ao_gps_decimal(1) >> 1));
+ } else
+ i = 255;
+ ao_gps_next.hdop = i;
+ ao_gps_skip_field();
+
+ ao_gps_next.altitude = ao_gps_decimal(0xff);
+ ao_gps_skip_field(); /* skip any fractional portion */
+
+ /* Skip remaining fields */
+ while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') {
+ ao_gps_lexchar();
+ ao_gps_skip_field();
+ }
+ if (ao_gps_char == '*') {
+ uint8_t cksum = ao_gps_cksum ^ '*';
+ if (cksum != ao_gps_hex(2))
+ ao_gps_error = 1;
+ } else
+ ao_gps_error = 1;
+ if (!ao_gps_error) {
+ ao_mutex_get(&ao_gps_mutex);
+ ao_gps_tick = ao_gps_next_tick;
+ memcpy(&ao_gps_data, &ao_gps_next, sizeof (ao_gps_data));
+ ao_mutex_put(&ao_gps_mutex);
+ ao_wakeup(&ao_gps_data);
+ }
+}
+
+static void
+ao_nmea_gsv(void)
+{
+ char c;
+ uint8_t i;
+ uint8_t done;
+ /* Now read the data into the GPS tracking data record
+ *
+ * $GPGSV,3,1,12,05,54,069,45,12,44,061,44,21,07,184,46,22,78,289,47*72<CR><LF>
+ *
+ * Satellites in view data
+ *
+ * 3 Total number of GSV messages
+ * 1 Sequence number of current GSV message
+ * 12 Total sats in view (0-12)
+ * 05 SVID
+ * 54 Elevation
+ * 069 Azimuth
+ * 45 C/N0 in dB
+ * ... other SVIDs
+ * 72 checksum
+ */
+ c = ao_gps_decimal(1); /* total messages */
+ i = ao_gps_decimal(1); /* message sequence */
+ if (i == 1) {
+ ao_gps_tracking_next.channels = 0;
+ }
+ done = (uint8_t) c == i;
+ ao_gps_lexchar();
+ ao_gps_skip_field(); /* sats in view */
+ while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') {
+ i = ao_gps_tracking_next.channels;
+ c = ao_gps_decimal(2); /* SVID */
+ if (i < AO_MAX_GPS_TRACKING)
+ ao_gps_tracking_next.sats[i].svid = c;
+ ao_gps_lexchar();
+ ao_gps_skip_field(); /* elevation */
+ ao_gps_lexchar();
+ ao_gps_skip_field(); /* azimuth */
+ c = ao_gps_decimal(2); /* C/N0 */
+ if (i < AO_MAX_GPS_TRACKING) {
+ if ((ao_gps_tracking_next.sats[i].c_n_1 = c) != 0)
+ ao_gps_tracking_next.channels = i + 1;
+ }
+ }
+ if (ao_gps_char == '*') {
+ uint8_t cksum = ao_gps_cksum ^ '*';
+ if (cksum != ao_gps_hex(2))
+ ao_gps_error = 1;
+ }
+ else
+ ao_gps_error = 1;
+ if (ao_gps_error)
+ ao_gps_tracking_next.channels = 0;
+ else if (done) {
+ ao_mutex_get(&ao_gps_mutex);
+ memcpy(&ao_gps_tracking_data, &ao_gps_tracking_next,
+ sizeof(ao_gps_tracking_data));
+ ao_mutex_put(&ao_gps_mutex);
+ ao_wakeup(&ao_gps_tracking_data);
+ }
+}
+
+static void
+ao_nmea_rmc(void)
+{
+ char a, c;
+ uint8_t i;
+ /* Parse the RMC record to read out the current date */
+
+ /* $GPRMC,111636.932,A,2447.0949,N,12100.5223,E,000.0,000.0,030407,,,A*61
+ *
+ * Recommended Minimum Specific GNSS Data
+ *
+ * 111636.932 UTC time 11:16:36.932
+ * A Data Valid (V = receiver warning)
+ * 2447.0949 Latitude
+ * N North/south indicator
+ * 12100.5223 Longitude
+ * E East/west indicator
+ * 000.0 Speed over ground
+ * 000.0 Course over ground
+ * 030407 UTC date (ddmmyy format)
+ * A Mode indicator:
+ * N = data not valid
+ * A = autonomous mode
+ * D = differential mode
+ * E = estimated (dead reckoning) mode
+ * M = manual input mode
+ * S = simulator mode
+ * 61 checksum
+ */
+ ao_gps_skip_field();
+ for (i = 0; i < 8; i++) {
+ ao_gps_lexchar();
+ ao_gps_skip_field();
+ }
+ a = ao_gps_decimal(2);
+ c = ao_gps_decimal(2);
+ i = ao_gps_decimal(2);
+ /* Skip remaining fields */
+ while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') {
+ ao_gps_lexchar();
+ ao_gps_skip_field();
+ }
+ if (ao_gps_char == '*') {
+ uint8_t cksum = ao_gps_cksum ^ '*';
+ if (cksum != ao_gps_hex(2))
+ ao_gps_error = 1;
+ } else
+ ao_gps_error = 1;
+ if (!ao_gps_error) {
+ ao_gps_next.year = i;
+ ao_gps_next.month = c;
+ ao_gps_next.day = a;
+ ao_gps_date_flags = AO_GPS_DATE_VALID;
+ }
+}
+
+#define ao_skytraq_sendstruct(s) ao_skytraq_sendbytes((s), sizeof(s))
+
+static void
+ao_skytraq_sendbytes(__code uint8_t *b, uint8_t l)
+{
+ while (l--) {
+ uint8_t c = *b++;
+ if (c == 0xa0)
+ ao_delay(AO_MS_TO_TICKS(500));
+ ao_serial_putchar(c);
+ }
+}
+
+static void
+ao_gps_nmea_parse(void)
+{
+ uint8_t a, b, c;
+
+ ao_gps_cksum = 0;
+ ao_gps_error = 0;
+
+ for (a = 0; a < AO_GPS_LEADER; a++) {
+ ao_gps_lexchar();
+ if (ao_gps_char != ao_gps_header[a])
+ return;
+ }
+
+ ao_gps_lexchar();
+ a = ao_gps_char;
+ ao_gps_lexchar();
+ b = ao_gps_char;
+ ao_gps_lexchar();
+ c = ao_gps_char;
+ ao_gps_lexchar();
+
+ if (ao_gps_char != ',')
+ return;
+
+ if (a == (uint8_t) 'G' && b == (uint8_t) 'G' && c == (uint8_t) 'A') {
+ ao_nmea_gga();
+ } else if (a == (uint8_t) 'G' && b == (uint8_t) 'S' && c == (uint8_t) 'V') {
+ ao_nmea_gsv();
+ } else if (a == (uint8_t) 'R' && b == (uint8_t) 'M' && c == (uint8_t) 'C') {
+ ao_nmea_rmc();
+ }
+}
+
+void
+ao_gps(void) __reentrant
+{
+ ao_serial_set_speed(AO_SERIAL_SPEED_9600);
+
+ /* give skytraq time to boot in case of cold start */
+ ao_delay(AO_MS_TO_TICKS(2000));
+
+ ao_skytraq_sendstruct(ao_gps_config);
+
+ for (;;) {
+ /* Locate the begining of the next record */
+ if (ao_serial_getchar() == '$') {
+ ao_gps_nmea_parse();
+ }
+
+ }
+}
+
+__xdata struct ao_task ao_gps_task;
+
+static void
+gps_dump(void) __reentrant
+{
+ uint8_t i;
+ ao_mutex_get(&ao_gps_mutex);
+ printf ("Date: %02d/%02d/%02d\n", ao_gps_data.year, ao_gps_data.month, ao_gps_data.day);
+ printf ("Time: %02d:%02d:%02d\n", ao_gps_data.hour, ao_gps_data.minute, ao_gps_data.second);
+ printf ("Lat/Lon: %ld %ld\n", ao_gps_data.latitude, ao_gps_data.longitude);
+ printf ("Alt: %d\n", ao_gps_data.altitude);
+ printf ("Flags: 0x%x\n", ao_gps_data.flags);
+ printf ("Sats: %d", ao_gps_tracking_data.channels);
+ for (i = 0; i < ao_gps_tracking_data.channels; i++)
+ printf (" %d %d",
+ ao_gps_tracking_data.sats[i].svid,
+ ao_gps_tracking_data.sats[i].c_n_1);
+ printf ("\ndone\n");
+ ao_mutex_put(&ao_gps_mutex);
+}
+
+__code struct ao_cmds ao_gps_cmds[] = {
+ { gps_dump, "g\0Display GPS" },
+ { 0, NULL },
+};
+
+void
+ao_gps_init(void)
+{
+ ao_add_task(&ao_gps_task, ao_gps, "gps");
+ ao_cmd_register(&ao_gps_cmds[0]);
+}
--- /dev/null
+/*
+ * 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]);
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+#include "ao.h"
+
+/* Total bytes of available storage */
+__pdata uint32_t ao_storage_total;
+
+/* Block size - device is erased in these units. At least 256 bytes */
+__pdata uint32_t ao_storage_block;
+
+/* Byte offset of config block. Will be ao_storage_block bytes long */
+__pdata uint32_t ao_storage_config;
+
+/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */
+__pdata uint16_t ao_storage_unit;
+
+/*
+ * Each flash chip is arranged in 64kB sectors; the
+ * chip cannot erase in units smaller than that.
+ *
+ * Writing happens in units of 256 byte pages and
+ * can only change bits from 1 to 0. So, you can rewrite
+ * the same contents, or append to an existing page easily enough
+ */
+
+#define M25_WREN 0x06 /* Write Enable */
+#define M25_WRDI 0x04 /* Write Disable */
+#define M25_RDID 0x9f /* Read Identification */
+#define M25_RDSR 0x05 /* Read Status Register */
+#define M25_WRSR 0x01 /* Write Status Register */
+#define M25_READ 0x03 /* Read Data Bytes */
+#define M25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
+#define M25_PP 0x02 /* Page Program */
+#define M25_SE 0xd8 /* Sector Erase */
+#define M25_BE 0xc7 /* Bulk Erase */
+#define M25_DP 0xb9 /* Deep Power-down */
+
+/* RDID response */
+#define M25_MANUF_OFFSET 0
+#define M25_MEMORY_TYPE_OFFSET 1
+#define M25_CAPACITY_OFFSET 2
+#define M25_UID_OFFSET 3
+#define M25_CFI_OFFSET 4
+#define M25_RDID_LEN 4 /* that's all we need */
+
+#define M25_CAPACITY_128KB 0x11
+#define M25_CAPACITY_256KB 0x12
+#define M25_CAPACITY_512KB 0x13
+#define M25_CAPACITY_1MB 0x14
+#define M25_CAPACITY_2MB 0x15
+
+/*
+ * Status register bits
+ */
+
+#define M25_STATUS_SRWD (1 << 7) /* Status register write disable */
+#define M25_STATUS_BP_MASK (7 << 2) /* Block protect bits */
+#define M25_STATUS_BP_SHIFT (2)
+#define M25_STATUS_WEL (1 << 1) /* Write enable latch */
+#define M25_STATUS_WIP (1 << 0) /* Write in progress */
+
+/*
+ * On teleterra, the m25 chip select pins are
+ * wired on P0_0 through P0_3.
+ */
+
+#if M25_MAX_CHIPS > 1
+static uint8_t ao_m25_size[M25_MAX_CHIPS]; /* number of sectors in each chip */
+static uint8_t ao_m25_pin[M25_MAX_CHIPS]; /* chip select pin for each chip */
+static uint8_t ao_m25_numchips; /* number of chips detected */
+#endif
+static uint8_t ao_m25_total; /* total sectors available */
+static uint8_t ao_m25_wip; /* write in progress */
+
+static __xdata uint8_t ao_m25_mutex;
+
+/*
+ * This little array is abused to send and receive data. A particular
+ * caution -- the read and write addresses are written into the last
+ * three bytes of the array by ao_m25_set_page_address and then the
+ * first byte is used by ao_m25_wait_wip and ao_m25_write_enable, neither
+ * of which touch those last three bytes.
+ */
+
+static __xdata uint8_t ao_m25_instruction[4];
+
+#define M25_SELECT(cs) ao_spi_get_mask(SPI_CS_PORT,cs)
+#define M25_DESELECT(cs) ao_spi_put_mask(SPI_CS_PORT,cs)
+
+#define M25_BLOCK_SHIFT 16
+#define M25_BLOCK 65536L
+#define M25_POS_TO_SECTOR(pos) ((uint8_t) ((pos) >> M25_BLOCK_SHIFT))
+#define M25_SECTOR_TO_POS(sector) (((uint32_t) (sector)) << M25_BLOCK_SHIFT)
+
+/*
+ * Block until the specified chip is done writing
+ */
+static void
+ao_m25_wait_wip(uint8_t cs)
+{
+ if (ao_m25_wip & cs) {
+ M25_SELECT(cs);
+ ao_m25_instruction[0] = M25_RDSR;
+ ao_spi_send(ao_m25_instruction, 1);
+ do {
+ ao_spi_recv(ao_m25_instruction, 1);
+ } while (ao_m25_instruction[0] & M25_STATUS_WIP);
+ M25_DESELECT(cs);
+ ao_m25_wip &= ~cs;
+ }
+}
+
+/*
+ * Set the write enable latch so that page program and sector
+ * erase commands will work. Also mark the chip as busy writing
+ * so that future operations will block until the WIP bit goes off
+ */
+static void
+ao_m25_write_enable(uint8_t cs)
+{
+ M25_SELECT(cs);
+ ao_m25_instruction[0] = M25_WREN;
+ ao_spi_send(&ao_m25_instruction, 1);
+ M25_DESELECT(cs);
+ ao_m25_wip |= cs;
+}
+
+
+/*
+ * Returns the number of 64kB sectors
+ */
+static uint8_t
+ao_m25_read_capacity(uint8_t cs)
+{
+ uint8_t capacity;
+ M25_SELECT(cs);
+ ao_m25_instruction[0] = M25_RDID;
+ ao_spi_send(ao_m25_instruction, 1);
+ ao_spi_recv(ao_m25_instruction, M25_RDID_LEN);
+ M25_DESELECT(cs);
+
+ /* Check to see if the chip is present */
+ if (ao_m25_instruction[0] == 0xff)
+ return 0;
+ capacity = ao_m25_instruction[M25_CAPACITY_OFFSET];
+
+ /* Sanity check capacity number */
+ if (capacity < 0x11 || 0x1f < capacity)
+ return 0;
+ return 1 << (capacity - 0x10);
+}
+
+static uint8_t
+ao_m25_set_address(uint32_t pos)
+{
+ uint8_t chip;
+#if M25_MAX_CHIPS > 1
+ uint8_t size;
+
+ for (chip = 0; chip < ao_m25_numchips; chip++) {
+ size = ao_m25_size[chip];
+ if (M25_POS_TO_SECTOR(pos) < size)
+ break;
+ pos -= M25_SECTOR_TO_POS(size);
+ }
+ if (chip == ao_m25_numchips)
+ return 0xff;
+
+ chip = ao_m25_pin[chip];
+#else
+ chip = M25_CS_MASK;
+#endif
+ ao_m25_wait_wip(chip);
+
+ ao_m25_instruction[1] = pos >> 16;
+ ao_m25_instruction[2] = pos >> 8;
+ ao_m25_instruction[3] = pos;
+ return chip;
+}
+
+/*
+ * Scan the possible chip select lines
+ * to see which flash chips are connected
+ */
+static uint8_t
+ao_m25_scan(void)
+{
+#if M25_MAX_CHIPS > 1
+ uint8_t pin, size;
+#endif
+
+ if (ao_m25_total)
+ return 1;
+
+#if M25_MAX_CHIPS > 1
+ ao_m25_numchips = 0;
+ for (pin = 1; pin != 0; pin <<= 1) {
+ if (M25_CS_MASK & pin) {
+ size = ao_m25_read_capacity(pin);
+ if (size != 0) {
+ ao_m25_size[ao_m25_numchips] = size;
+ ao_m25_pin[ao_m25_numchips] = pin;
+ ao_m25_total += size;
+ ao_m25_numchips++;
+ }
+ }
+ }
+#else
+ ao_m25_total = ao_m25_read_capacity(M25_CS_MASK);
+#endif
+ if (!ao_m25_total)
+ return 0;
+ ao_storage_total = M25_SECTOR_TO_POS(ao_m25_total);
+ ao_storage_block = M25_BLOCK;
+ ao_storage_config = ao_storage_total - M25_BLOCK;
+ ao_storage_unit = 256;
+ return 1;
+}
+
+/*
+ * Erase the specified sector
+ */
+uint8_t
+ao_storage_erase(uint32_t pos) __reentrant
+{
+ uint8_t cs;
+
+ if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total)
+ return 0;
+
+ ao_mutex_get(&ao_m25_mutex);
+ ao_m25_scan();
+
+ cs = ao_m25_set_address(pos);
+
+ ao_m25_wait_wip(cs);
+ ao_m25_write_enable(cs);
+
+ ao_m25_instruction[0] = M25_SE;
+ M25_SELECT(cs);
+ ao_spi_send(ao_m25_instruction, 4);
+ M25_DESELECT(cs);
+ ao_m25_wip |= cs;
+
+ ao_mutex_put(&ao_m25_mutex);
+ return 1;
+}
+
+/*
+ * Write to flash
+ */
+uint8_t
+ao_storage_device_write(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
+{
+ uint8_t cs;
+
+ if (pos >= ao_storage_total || pos + len > ao_storage_total)
+ return 0;
+
+ ao_mutex_get(&ao_m25_mutex);
+ ao_m25_scan();
+
+ cs = ao_m25_set_address(pos);
+ ao_m25_write_enable(cs);
+
+ ao_m25_instruction[0] = M25_PP;
+ M25_SELECT(cs);
+ ao_spi_send(ao_m25_instruction, 4);
+ ao_spi_send(d, len);
+ M25_DESELECT(cs);
+
+ ao_mutex_put(&ao_m25_mutex);
+ return 1;
+}
+
+/*
+ * Read from flash
+ */
+uint8_t
+ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
+{
+ uint8_t cs;
+
+ if (pos >= ao_storage_total || pos + len > ao_storage_total)
+ return 0;
+ ao_mutex_get(&ao_m25_mutex);
+ ao_m25_scan();
+
+ cs = ao_m25_set_address(pos);
+
+ /* No need to use the FAST_READ as we're running at only 8MHz */
+ ao_m25_instruction[0] = M25_READ;
+ M25_SELECT(cs);
+ ao_spi_send(ao_m25_instruction, 4);
+ ao_spi_recv(d, len);
+ M25_DESELECT(cs);
+
+ ao_mutex_put(&ao_m25_mutex);
+ return 1;
+}
+
+void
+ao_storage_flush(void) __reentrant
+{
+}
+
+void
+ao_storage_setup(void)
+{
+ ao_mutex_get(&ao_m25_mutex);
+ ao_m25_scan();
+ ao_mutex_put(&ao_m25_mutex);
+}
+
+void
+ao_storage_device_info(void) __reentrant
+{
+ uint8_t cs;
+#if M25_MAX_CHIPS > 1
+ uint8_t chip;
+#endif
+
+ ao_mutex_get(&ao_m25_mutex);
+ ao_m25_scan();
+ ao_mutex_put(&ao_m25_mutex);
+
+#if M25_MAX_CHIPS > 1
+ printf ("Detected chips %d size %d\n", ao_m25_numchips, ao_m25_total);
+ for (chip = 0; chip < ao_m25_numchips; chip++)
+ printf ("Flash chip %d select %02x size %d\n",
+ chip, ao_m25_pin[chip], ao_m25_size[chip]);
+#else
+ printf ("Detected chips 1 size %d\n", ao_m25_total);
+#endif
+
+ printf ("Available chips:\n");
+ for (cs = 1; cs != 0; cs <<= 1) {
+ if ((M25_CS_MASK & cs) == 0)
+ continue;
+
+ ao_mutex_get(&ao_m25_mutex);
+ M25_SELECT(cs);
+ ao_m25_instruction[0] = M25_RDID;
+ ao_spi_send(ao_m25_instruction, 1);
+ ao_spi_recv(ao_m25_instruction, M25_RDID_LEN);
+ M25_DESELECT(cs);
+
+ printf ("Select %02x manf %02x type %02x cap %02x uid %02x\n",
+ cs,
+ ao_m25_instruction[M25_MANUF_OFFSET],
+ ao_m25_instruction[M25_MEMORY_TYPE_OFFSET],
+ ao_m25_instruction[M25_CAPACITY_OFFSET],
+ ao_m25_instruction[M25_UID_OFFSET]);
+ ao_mutex_put(&ao_m25_mutex);
+ }
+}
+
+void
+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
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+ }
+}
+++ /dev/null
-#!/usr/bin/env nickle
-
-int checksum(string a)
-{
- int c = 0;
- for (int i = 0; i < String::length(a); i++)
- c ^= a[i];
- return c;
-}
-
-void main()
-{
- for (int i = 1; i < dim(argv); i++)
- printf ("$%s*%02x\n", argv[i], checksum(argv[i]));
-}
-
-main();
+++ /dev/null
-#!/usr/bin/nickle -f
-/*
- * Pressure Sensor Model, version 1.1
- *
- * written by Holly Grimes
- *
- * Uses the International Standard Atmosphere as described in
- * "A Quick Derivation relating altitude to air pressure" (version 1.03)
- * from the Portland State Aerospace Society, except that the atmosphere
- * is divided into layers with each layer having a different lapse rate.
- *
- * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007
- * at site <http://en.wikipedia.org/wiki/International_Standard_Atmosphere
- *
- * Height measurements use the local tangent plane. The postive z-direction is up.
- *
- * All measurements are given in SI units (Kelvin, Pascal, meter, meters/second^2).
- * The lapse rate is given in Kelvin/meter, the gas constant for air is given
- * in Joules/(kilogram-Kelvin).
- */
-
-const real GRAVITATIONAL_ACCELERATION = -9.80665;
-const real AIR_GAS_CONSTANT = 287.053;
-const int NUMBER_OF_LAYERS = 7;
-const real MAXIMUM_ALTITUDE = 84852;
-const real MINIMUM_PRESSURE = 0.3734;
-const real LAYER0_BASE_TEMPERATURE = 288.15;
-const real LAYER0_BASE_PRESSURE = 101325;
-
-/* lapse rate and base altitude for each layer in the atmosphere */
-const real[NUMBER_OF_LAYERS] lapse_rate = {
- -0.0065, 0.0, 0.001, 0.0028, 0.0, -0.0028, -0.002
-};
-const int[NUMBER_OF_LAYERS] base_altitude = {
- 0, 11000, 20000, 32000, 47000, 51000, 71000
-};
-
-
-/* outputs atmospheric pressure associated with the given altitude. altitudes
- are measured with respect to the mean sea level */
-real altitude_to_pressure(real altitude) {
-
- real base_temperature = LAYER0_BASE_TEMPERATURE;
- real base_pressure = LAYER0_BASE_PRESSURE;
-
- real pressure;
- real base; /* base for function to determine pressure */
- real exponent; /* exponent for function to determine pressure */
- int layer_number; /* identifies layer in the atmosphere */
- int delta_z; /* difference between two altitudes */
-
- if (altitude > MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */
- return 0;
-
- /* calculate the base temperature and pressure for the atmospheric layer
- associated with the inputted altitude */
- for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) {
- delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
- if (lapse_rate[layer_number] == 0.0) {
- exponent = GRAVITATIONAL_ACCELERATION * delta_z
- / AIR_GAS_CONSTANT / base_temperature;
- base_pressure *= exp(exponent);
- }
- else {
- base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
- exponent = GRAVITATIONAL_ACCELERATION /
- (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
- base_pressure *= pow(base, exponent);
- }
- base_temperature += delta_z * lapse_rate[layer_number];
- }
-
- /* calculate the pressure at the inputted altitude */
- delta_z = altitude - base_altitude[layer_number];
- if (lapse_rate[layer_number] == 0.0) {
- exponent = GRAVITATIONAL_ACCELERATION * delta_z
- / AIR_GAS_CONSTANT / base_temperature;
- pressure = base_pressure * exp(exponent);
- }
- else {
- base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
- exponent = GRAVITATIONAL_ACCELERATION /
- (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
- pressure = base_pressure * pow(base, exponent);
- }
-
- return pressure;
-}
-
-
-/* outputs the altitude associated with the given pressure. the altitude
- returned is measured with respect to the mean sea level */
-real pressure_to_altitude(real pressure) {
-
- real next_base_temperature = LAYER0_BASE_TEMPERATURE;
- real next_base_pressure = LAYER0_BASE_PRESSURE;
-
- real altitude;
- real base_pressure;
- real base_temperature;
- real base; /* base for function to determine base pressure of next layer */
- real exponent; /* exponent for function to determine base pressure
- of next layer */
- real coefficient;
- int layer_number; /* identifies layer in the atmosphere */
- int delta_z; /* difference between two altitudes */
-
- if (pressure < 0) /* illegal pressure */
- return -1;
- if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */
- return MAXIMUM_ALTITUDE;
-
- /* calculate the base temperature and pressure for the atmospheric layer
- associated with the inputted pressure. */
- layer_number = -1;
- do {
- layer_number++;
- base_pressure = next_base_pressure;
- base_temperature = next_base_temperature;
- delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
- if (lapse_rate[layer_number] == 0.0) {
- exponent = GRAVITATIONAL_ACCELERATION * delta_z
- / AIR_GAS_CONSTANT / base_temperature;
- next_base_pressure *= exp(exponent);
- }
- else {
- base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
- exponent = GRAVITATIONAL_ACCELERATION /
- (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
- next_base_pressure *= pow(base, exponent);
- }
- next_base_temperature += delta_z * lapse_rate[layer_number];
- }
- while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure);
-
- /* calculate the altitude associated with the inputted pressure */
- if (lapse_rate[layer_number] == 0.0) {
- coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION)
- * base_temperature;
- altitude = base_altitude[layer_number]
- + coefficient * log(pressure / base_pressure);
- }
- else {
- base = pressure / base_pressure;
- exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number]
- / GRAVITATIONAL_ACCELERATION;
- coefficient = base_temperature / lapse_rate[layer_number];
- altitude = base_altitude[layer_number]
- + coefficient * (pow(base, exponent) - 1);
- }
-
- return altitude;
-}
-
-real feet_to_meters(real feet)
-{
- return feet * (12 * 2.54 / 100);
-}
-
-real meters_to_feet(real meters)
-{
- return meters / (12 * 2.54 / 100);
-}
-
-/*
- * Values for our MP3H6115A pressure sensor
- *
- * From the data sheet:
- *
- * Pressure range: 15-115 kPa
- * Voltage at 115kPa: 2.82
- * Output scale: 27mV/kPa
- *
- *
- * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa
- * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa
- */
-
-real counts_per_kPa = 27 * 2047 / 3300;
-real counts_at_101_3kPa = 1674;
-
-real fraction_to_kPa(real fraction)
-{
- return (fraction + 0.095) / 0.009;
-}
-
-
-real count_to_kPa(real count) = fraction_to_kPa(count / 2047);
-
-typedef struct {
- real m, b;
- int m_i, b_i;
-} line_t;
-
-line_t best_fit(real[] values, int first, int last) {
- real sum_x = 0, sum_x2 = 0, sum_y = 0, sum_xy = 0;
- int n = last - first + 1;
- real m, b;
- int m_i, b_i;
-
- for (int i = first; i <= last; i++) {
- sum_x += i;
- sum_x2 += i**2;
- sum_y += values[i];
- sum_xy += values[i] * i;
- }
- m = (n*sum_xy - sum_y*sum_x) / (n*sum_x2 - sum_x**2);
- b = sum_y/n - m*(sum_x/n);
- return (line_t) { m = m, b = b };
-}
-
-real count_to_altitude(real count) {
- return pressure_to_altitude(count_to_kPa(count) * 1000);
-}
-
-real fraction_to_altitude(real frac) = pressure_to_altitude(fraction_to_kPa(frac) * 1000);
-
-int num_samples = 1024;
-
-real[num_samples] alt = { [n] = fraction_to_altitude(n/(num_samples - 1)) };
-
-int num_part = 128;
-int seg_len = num_samples / num_part;
-
-line_t [dim(alt) / seg_len] fit = {
- [n] = best_fit(alt, n * seg_len, n * seg_len + seg_len - 1)
-};
-
-int[num_samples/seg_len + 1] alt_part;
-
-alt_part[0] = floor (fit[0].b + 0.5);
-alt_part[dim(fit)] = floor(fit[dim(fit)-1].m * dim(fit) * seg_len + fit[dim(fit)-1].b + 0.5);
-
-for (int i = 0; i < dim(fit) - 1; i++) {
- real here, there;
- here = fit[i].m * (i+1) * seg_len + fit[i].b;
- there = fit[i+1].m * (i+1) * seg_len + fit[i+1].b;
- alt_part[i+1] = floor ((here + there) / 2 + 0.5);
-}
-
-real count_to_fit_altitude(int count) {
- int sub = count // seg_len;
- int off = count % seg_len;
- line_t l = fit[sub];
- real r_v;
- real i_v;
-
- r_v = count * l.m + l.b;
- i_v = (alt_part[sub] * (seg_len - off) + alt_part[sub+1] * off) / seg_len;
- return i_v;
-}
-
-real max_error = 0;
-int max_error_count = 0;
-real total_error = 0;
-
-for (int count = 0; count < num_samples; count++) {
- real kPa = fraction_to_kPa(count / (num_samples - 1));
- real meters = pressure_to_altitude(kPa * 1000);
-
- real meters_approx = count_to_fit_altitude(count);
- real error = abs(meters - meters_approx);
-
- total_error += error;
- if (error > max_error) {
- max_error = error;
- max_error_count = count;
- }
-# printf (" %7d, /* %6.2g kPa %5d count approx %d */\n",
-# floor (meters + 0.5), kPa, count, floor(count_to_fit_altitude(count) + 0.5));
-}
-
-printf ("/*max error %f at %7.3f%%. Average error %f*/\n", max_error, max_error_count / (num_samples - 1) * 100, total_error / num_samples);
-
-printf ("#define NALT %d\n", dim(alt_part));
-printf ("#define ALT_FRAC_BITS %d\n", floor (log2(32768/(dim(alt_part)-1)) + 0.1));
-
-for (int i = 0; i < dim(alt_part); i++) {
- real fraction = i / (dim(alt_part) - 1);
- real kPa = fraction_to_kPa(fraction);
- printf ("%9d, /* %6.2f kPa %7.3f%% */\n",
- alt_part[i], kPa, fraction * 100);
-}
+++ /dev/null
-#!/bin/sh
-
-cd ../kalman
-
-SIGMA_BOTH="-M 2 -H 6 -A 2"
-SIGMA_BARO="-M 2 -H 6 -A 2"
-SIGMA_ACCEL="-M 2 -H 4 -A 4"
-
-nickle kalman.5c -p AO_BOTH -c both -t 0.01 $SIGMA_BOTH
-nickle kalman.5c -p AO_BOTH -c both -t 0.1 $SIGMA_BOTH
-nickle kalman.5c -p AO_BOTH -c both -t 1 $SIGMA_BOTH
-
-nickle kalman.5c -p AO_ACCEL -c accel -t 0.01 $SIGMA_ACCEL
-nickle kalman.5c -p AO_ACCEL -c accel -t 0.1 $SIGMA_ACCEL
-nickle kalman.5c -p AO_ACCEL -c accel -t 1 $SIGMA_ACCEL
-
-nickle kalman.5c -p AO_BARO -c baro -t 0.01 $SIGMA_BARO
-nickle kalman.5c -p AO_BARO -c baro -t 0.1 $SIGMA_BARO
-nickle kalman.5c -p AO_BARO -c baro -t 1 $SIGMA_BARO
--- /dev/null
+#
+# 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:
--- /dev/null
+#
+# 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:
--- /dev/null
+#
+# 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:
--- /dev/null
+#
+# 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:
--- /dev/null
+#
+# 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:
--- /dev/null
+#
+# 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:
--- /dev/null
+/*
+ * 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_NONE; /* until we actually log stuff */
+
+void
+main(void)
+{
+ ao_clock_init();
+
+ /* Turn on the LED until the system is stable */
+ ao_led_init(LEDS_AVAILABLE);
+ ao_led_on(AO_LED_RED);
+ ao_timer_init();
+#if HAS_BEEP
+ ao_beep_init();
+#endif
+ ao_cmd_init();
+#if HAS_EEPROM
+ ao_spi_init();
+ ao_storage_init();
+#endif
+ ao_usb_init();
+ 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();
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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
+main(void)
+{
+ ao_clock_init();
+
+ /* Turn on the LED until the system is stable */
+ ao_led_init(LEDS_AVAILABLE);
+ ao_led_on(AO_LED_RED);
+ ao_timer_init();
+ ao_cmd_init();
+ ao_usb_init();
+ ao_monitor_init(AO_LED_GREEN, TRUE);
+ ao_rssi_init(AO_LED_RED);
+ ao_radio_init();
+ ao_packet_master_init();
+#if HAS_DBG
+ ao_dbg_init();
+#endif
+ ao_aes_init();
+ ao_radio_cmac_init();
+ ao_config_init();
+ ao_start_scheduler();
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_pins.h"
+
+void
+main(void)
+{
+ /*
+ * Reduce the transient on the ignite pins at startup by
+ * pulling the pins low as soon as possible at power up
+ */
+ ao_ignite_set_pins();
+
+ ao_clock_init();
+
+ /* Turn on the red LED until the system is stable */
+ ao_led_init(LEDS_AVAILABLE);
+ ao_led_on(AO_LED_RED);
+
+ /* A hack -- look at the SPI clock pin, if it's sitting at
+ * ground, then we force the computer to idle mode instead of
+ * flight mode
+ */
+ if (P1_3 == 0) {
+ ao_flight_force_idle = 1;
+ while (P1_3 == 0)
+ ;
+ }
+ ao_timer_init();
+ ao_adc_init();
+ ao_beep_init();
+ ao_cmd_init();
+ ao_spi_init();
+ ao_storage_init();
+ ao_flight_init();
+ ao_log_init();
+ ao_report_init();
+ ao_usb_init();
+ ao_serial_init();
+ ao_gps_init();
+ ao_gps_report_init();
+ ao_telemetry_init();
+ ao_radio_init();
+ ao_packet_slave_init(FALSE);
+ ao_igniter_init();
+#if HAS_DBG
+ ao_dbg_init();
+#endif
+#if HAS_COMPANION
+ ao_companion_init();
+#endif
+ ao_config_init();
+ ao_start_scheduler();
+}
--- /dev/null
+/*
+ * 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_pins.h"
+
+void
+main(void)
+{
+ /*
+ * Reduce the transient on the ignite pins at startup by
+ * pulling the pins low as soon as possible at power up
+ */
+ ao_ignite_set_pins();
+
+ ao_clock_init();
+
+ /* Turn on the red LED until the system is stable */
+ ao_led_init(LEDS_AVAILABLE);
+ ao_led_on(AO_LED_RED);
+
+ ao_timer_init();
+ ao_adc_init();
+ ao_cmd_init();
+ ao_storage_init();
+ ao_flight_init();
+ ao_log_init();
+ ao_report_init();
+ ao_telemetry_init();
+ ao_radio_init();
+ ao_packet_slave_init(TRUE);
+ ao_igniter_init();
+ ao_config_init();
+ ao_start_scheduler();
+}
--- /dev/null
+/*
+ * 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_pins.h"
+
+void
+main(void)
+{
+ ao_clock_init();
+
+
+ /* Turn on the red LED until the system is stable */
+ ao_led_init(LEDS_AVAILABLE);
+ ao_led_on(AO_LED_RED);
+
+ ao_timer_init();
+ ao_adc_init();
+ ao_cmd_init();
+ ao_storage_init();
+ ao_flight_nano_init();
+ ao_log_init();
+ ao_report_init();
+ ao_telemetry_init();
+ ao_radio_init();
+ ao_packet_slave_init(TRUE);
+ ao_config_init();
+ ao_start_scheduler();
+}
--- /dev/null
+/*
+ * 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_slave_init();
+ ao_usb_init();
+ ao_adc_init();
+ ao_start_scheduler();
+ return 0;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#define AO_NO_ADC_ISR 1
+#include "ao.h"
+
+void
+main(void)
+{
+ ao_clock_init();
+
+ /* Turn on the red LED until the system is stable */
+ ao_led_init(AO_LED_RED|AO_LED_GREEN);
+ ao_led_on(AO_LED_RED);
+ ao_timer_init();
+ ao_beep_init();
+ ao_cmd_init();
+ ao_usb_init();
+ ao_serial_init();
+ ao_monitor_init(AO_LED_GREEN, TRUE);
+ ao_radio_init();
+ ao_config_init();
+ ao_start_scheduler();
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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 __xdata blink_0_task;
+struct ao_task __xdata blink_1_task;
+struct ao_task __xdata wakeup_task;
+struct ao_task __xdata beep_task;
+struct ao_task __xdata echo_task;
+
+void delay(int n) __reentrant
+{
+ uint8_t j = 0;
+ while (--n)
+ while (--j)
+ ao_yield();
+}
+
+static __xdata uint8_t blink_chan;
+
+void
+blink_0(void)
+{
+ uint8_t b = 0;
+ for (;;) {
+ b = 1 - b;
+ if (b)
+ ao_led_on(AO_LED_GREEN);
+ else
+ ao_led_off(AO_LED_GREEN);
+ ao_sleep(&blink_chan);
+ }
+}
+
+void
+blink_1(void)
+{
+ static __xdata struct ao_adc adc;
+
+ for (;;) {
+ ao_sleep(&ao_adc_head);
+ ao_adc_get(&adc);
+ if (adc.accel < 15900)
+ ao_led_on(AO_LED_RED);
+ else
+ ao_led_off(AO_LED_RED);
+ }
+}
+
+void
+wakeup(void)
+{
+ for (;;) {
+ ao_delay(AO_MS_TO_TICKS(100));
+ ao_wakeup(&blink_chan);
+ }
+}
+
+void
+beep(void)
+{
+ static __xdata struct ao_adc adc;
+
+ for (;;) {
+ ao_delay(AO_SEC_TO_TICKS(1));
+ ao_adc_get(&adc);
+ if (adc.temp > 7400)
+ ao_beep_for(AO_BEEP_LOW, AO_MS_TO_TICKS(50));
+ }
+}
+
+void
+echo(void)
+{
+ char c;
+ for (;;) {
+ ao_usb_flush();
+ c = ao_usb_getchar();
+ ao_usb_putchar(c);
+ if (c == '\r')
+ ao_usb_putchar('\n');
+ }
+}
+
+void
+main(void)
+{
+ ao_clock_init();
+
+// ao_add_task(&blink_0_task, blink_0);
+// ao_add_task(&blink_1_task, blink_1);
+// ao_add_task(&wakeup_task, wakeup);
+// ao_add_task(&beep_task, beep);
+ ao_add_task(&echo_task, echo);
+ ao_timer_init();
+ ao_adc_init();
+ ao_beep_init();
+ ao_led_init();
+ ao_usb_init();
+
+ ao_start_scheduler();
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#define AO_NO_SERIAL_ISR 1
+#define AO_NO_ADC_ISR 1
+#include "ao.h"
+
+void
+main(void)
+{
+ ao_clock_init();
+
+ /* Turn on the LED until the system is stable */
+ ao_led_init(AO_LED_RED);
+ ao_led_on(AO_LED_RED);
+ ao_timer_init();
+ ao_cmd_init();
+ ao_usb_init();
+ ao_monitor_init(AO_LED_RED, TRUE);
+ 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;
+ P1 |= 1;
+ ao_start_scheduler();
+}
+++ /dev/null
-#!/usr/bin/env nickle
-
-int checksum(int[] msg)
-{
- int sum = 0;
- for (int i = 0; i < dim(msg); i++) {
- sum += msg[i];
- sum &= 0x7fff;
- }
- return sum;
-}
-
-void main()
-{
- string[...] input;
- int[...] msg;
-
- setdim(input, 0);
- while (!File::end(stdin)) {
- input[dim(input)] = gets();
- }
-
- setdim(msg, 0);
- for (int i = 0; i < dim(input); i++) {
- string[*] words = String::wordsplit(input[i], " ,\t");
- for (int j = 0; j < dim(words); j++) {
- if (words[j] == "/" + "*")
- break;
- if (String::length(words[j]) > 0 &&
- Ctype::isdigit(words[j][0])) {
- msg[dim(msg)] = string_to_integer(words[j]);
- }
- }
- }
- printf("\t0xa0, 0xa2, 0x%02x, 0x%02x,\t/* length: %d bytes */\n",
- dim(msg) >> 8, dim(msg) & 0xff, dim(msg));
- for (int i = 0; i < dim(input); i++)
- printf("%s\n", input[i]);
- int csum = checksum(msg);
- printf ("\t0x%02x, 0x%02x, 0xb0, 0xb3,\n",
- csum >> 8, csum & 0xff);
-}
-
-main();
+++ /dev/null
-#!/usr/bin/env nickle
-
-int checksum(int[] msg)
-{
- int sum = 0;
- for (int i = 0; i < dim(msg); i++) {
- sum ^= msg[i];
- sum &= 0xff;
- }
- return sum;
-}
-
-void main()
-{
- string[...] input;
- int[...] msg;
-
- setdim(input, 0);
- while (!File::end(stdin)) {
- input[dim(input)] = gets();
- }
-
- setdim(msg, 0);
- for (int i = 0; i < dim(input); i++) {
- string[*] words = String::wordsplit(input[i], " ,\t");
- for (int j = 0; j < dim(words); j++) {
- if (words[j] == "/" + "*")
- break;
- if (String::length(words[j]) > 0 &&
- Ctype::isdigit(words[j][0])) {
- msg[dim(msg)] = string_to_integer(words[j]);
- }
- }
- }
- printf("\t0xa0, 0xa1, 0x%02x, 0x%02x,\t\t/* length: %d bytes */\n",
- dim(msg) >> 8, dim(msg) & 0xff, dim(msg));
- for (int i = 0; i < dim(input); i++)
- printf("%s\n", input[i]);
- int csum = checksum(msg);
- printf ("\t0x%02x, 0x0d, 0x0a,\n",
- csum);
-}
-
-main();
-include ../Makefile.proto
+#
+# TeleBT v0.0 build
+#
+
+TELEBT_VER=0.0
+TELEBT_DEF=0_0
+
+include ../product/Makefile.telebt
+
+++ /dev/null
-PROG = telebt-v0.0-$(VERSION).ihx
-
-SRC = \
- $(TBT_BASE_SRC)
-
-PRODUCT=TeleBT-v0.0
-PRODUCT_DEF=-DTELEBT_V_0_0
-IDPRODUCT=0x000e
-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
+
+++ /dev/null
-PROG = telebt-v0.1-$(VERSION).ihx
-
-SRC = \
- $(TBT_V_0_1_SRC)
-
-PRODUCT=TeleBT-v0.1
-PRODUCT_DEF=-DTELEBT_V_0_1
-IDPRODUCT=0x000e
--- /dev/null
+--directory=..
-include ../Makefile.proto
+#
+# TeleDongle v0.2 build
+#
+
+TD_VER=0.1
+TD_DEF=0_1
+
+include ../product/Makefile.teledongle
+++ /dev/null
-PROG = teledongle-v0.1-$(VERSION).ihx
-
-SRC = \
- $(TD_SRC) \
- $(DBG_SRC)
-
-PRODUCT=TeleDongle-v0.1
-PRODUCT_DEF=-DTELEDONGLE_V_0_1
-IDPRODUCT=0x000c
-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
+++ /dev/null
-PROG = teledongle-v0.2-$(VERSION).ihx
-
-SRC = \
- $(TD_SRC) \
- $(DBG_SRC)
-
-PRODUCT=TeleDongle-v0.2
-PRODUCT_DEF=-DTELEDONGLE_V_0_2
-IDPRODUCT=0x000c
--- /dev/null
+telemetrum-v0.1-sky*
+ao_product.h
--- /dev/null
+--directory=..
--- /dev/null
+TELELAUNCH_VER=0.1
+TELELAUNCH_DEF=0_1
+
+include ../product/Makefile.telelaunch
--- /dev/null
+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
-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
+
+++ /dev/null
-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
-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
+
+++ /dev/null
-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
-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
+++ /dev/null
-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
-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
+++ /dev/null
-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
-include ../Makefile.proto
+#
+# TeleMini build file
+#
+
+TELEMINI_VER=1.0
+TELEMINI_DEF=1_0
+
+include ../product/Makefile.telemini
+++ /dev/null
-PROG = telemini-v1.0-$(VERSION).ihx
-
-SRC = \
- $(TMINI_BASE_SRC)
-
-PRODUCT=TeleMini-v1.0
-PRODUCT_DEF=-DTELEMINI_V_1_0
-IDPRODUCT=0x000a
-CODESIZE=0x6700
-include ../Makefile.proto
+#
+# TeleNano build file
+#
+
+TELENANO_VER=0.1
+TELENANO_DEF=0_1
+
+include ../product/Makefile.telenano
+
+++ /dev/null
-PROG = telenano-v0.1-$(VERSION).ihx
-
-SRC = \
- $(TNANO_BASE_SRC)
-
-PRODUCT=TeleNano-v0.1
-PRODUCT_DEF=-DTELENANO_V_0_1
-IDPRODUCT=0x000a
-CODESIZE=0x6700
--- /dev/null
+#
+# 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
--- /dev/null
+#
+# 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
-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)
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 $@ $<
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <math.h>
+
+#define AO_HERTZ 100
+
+#define AO_ADC_RING 64
+#define ao_adc_ring_next(n) (((n) + 1) & (AO_ADC_RING - 1))
+#define ao_adc_ring_prev(n) (((n) - 1) & (AO_ADC_RING - 1))
+
+#define AO_M_TO_HEIGHT(m) ((int16_t) (m))
+#define AO_MS_TO_SPEED(ms) ((int16_t) ((ms) * 16))
+#define AO_MSS_TO_ACCEL(mss) ((int16_t) ((mss) * 16))
+
+/*
+ * One set of samples read from the A/D converter
+ */
+struct ao_adc {
+ uint16_t tick; /* tick when the sample was read */
+ int16_t accel; /* accelerometer */
+ int16_t pres; /* pressure sensor */
+ int16_t pres_real; /* unclipped */
+ 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 __pdata
+#define __data
+#define __xdata
+#define __code
+#define __reentrant
+
+#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5))
+#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5))
+#define from_fix(x) ((x) >> 16)
+
+/*
+ * Above this height, the baro sensor doesn't work
+ */
+#define AO_MAX_BARO_HEIGHT 12000
+#define AO_BARO_SATURATE 13000
+#define AO_MIN_BARO_VALUE ao_altitude_to_pres(AO_BARO_SATURATE)
+
+/*
+ * Above this speed, baro measurements are unreliable
+ */
+#define AO_MAX_BARO_SPEED 200
+
+#define ACCEL_NOSE_UP (ao_accel_2g >> 2)
+
+enum ao_flight_state {
+ ao_flight_startup = 0,
+ ao_flight_idle = 1,
+ ao_flight_pad = 2,
+ ao_flight_boost = 3,
+ ao_flight_fast = 4,
+ ao_flight_coast = 5,
+ ao_flight_drogue = 6,
+ ao_flight_main = 7,
+ ao_flight_landed = 8,
+ ao_flight_invalid = 9
+};
+
+extern enum ao_flight_state ao_flight_state;
+
+#define FALSE 0
+#define TRUE 1
+
+struct ao_adc ao_adc_ring[AO_ADC_RING];
+uint8_t ao_adc_head;
+int ao_summary = 0;
+
+#define ao_led_on(l)
+#define ao_led_off(l)
+#define ao_timer_set_adc_interval(i)
+#define ao_wakeup(wchan) ao_dump_state()
+#define ao_cmd_register(c)
+#define ao_usb_disable()
+#define ao_telemetry_set_interval(x)
+#define ao_rdf_set(rdf)
+#define ao_packet_slave_start()
+#define ao_packet_slave_stop()
+
+enum ao_igniter {
+ ao_igniter_drogue = 0,
+ ao_igniter_main = 1
+};
+
+struct ao_adc ao_adc_static;
+
+int drogue_height;
+double drogue_time;
+int main_height;
+double main_time;
+
+int tick_offset;
+
+static int32_t ao_k_height;
+
+void
+ao_ignite(enum ao_igniter igniter)
+{
+ double time = (double) (ao_adc_static.tick + tick_offset) / 100;
+
+ if (igniter == ao_igniter_drogue) {
+ drogue_time = time;
+ drogue_height = ao_k_height >> 16;
+ } else {
+ main_time = time;
+ main_height = ao_k_height >> 16;
+ }
+}
+
+struct ao_task {
+ int dummy;
+};
+
+#define ao_add_task(t,f,n)
+
+#define ao_log_start()
+#define ao_log_stop()
+
+#define AO_MS_TO_TICKS(ms) ((ms) / 10)
+#define AO_SEC_TO_TICKS(s) ((s) * 100)
+
+#define AO_FLIGHT_TEST
+
+int ao_flight_debug;
+
+FILE *emulator_in;
+char *emulator_app;
+char *emulator_name;
+double emulator_error_max = 4;
+double emulator_height_error_max = 20; /* noise in the baro sensor */
+
+void
+ao_dump_state(void);
+
+void
+ao_sleep(void *wchan);
+
+const char const * const ao_state_names[] = {
+ "startup", "idle", "pad", "boost", "fast",
+ "coast", "drogue", "main", "landed", "invalid"
+};
+
+struct ao_cmds {
+ void (*func)(void);
+ const char *help;
+};
+
+#include "ao_convert.c"
+
+struct ao_config {
+ uint16_t main_deploy;
+ int16_t accel_plus_g;
+ int16_t accel_minus_g;
+ uint8_t pad_orientation;
+};
+
+#define AO_PAD_ORIENTATION_ANTENNA_UP 0
+#define AO_PAD_ORIENTATION_ANTENNA_DOWN 1
+
+#define ao_config_get()
+
+struct ao_config ao_config;
+
+#define DATA_TO_XDATA(x) (x)
+
+#define HAS_FLIGHT 1
+#define HAS_ADC 1
+#define HAS_USB 1
+#define HAS_GPS 1
+#ifndef HAS_ACCEL
+#define HAS_ACCEL 1
+#define HAS_ACCEL_REF 0
+#endif
+
+#define GRAVITY 9.80665
+extern int16_t ao_ground_accel, ao_flight_accel;
+extern int16_t ao_accel_2g;
+
+extern uint16_t ao_sample_tick;
+
+extern int16_t ao_sample_height;
+extern int16_t ao_sample_accel;
+extern int32_t ao_accel_scale;
+extern int16_t ao_ground_height;
+extern int16_t ao_sample_alt;
+
+int ao_sample_prev_tick;
+uint16_t prev_tick;
+
+#include "ao_kalman.c"
+#include "ao_sample.c"
+#include "ao_flight.c"
+
+#define to_double(f) ((f) / 65536.0)
+
+static int ao_records_read = 0;
+static int ao_eof_read = 0;
+static int ao_flight_ground_accel;
+static int ao_flight_started = 0;
+static int ao_test_max_height;
+static double ao_test_max_height_time;
+static int ao_test_main_height;
+static double ao_test_main_height_time;
+static double ao_test_landed_time;
+static double ao_test_landed_height;
+static double ao_test_landed_time;
+static int landed_set;
+static double landed_time;
+static double landed_height;
+
+void
+ao_test_exit(void)
+{
+ double drogue_error;
+ double main_error;
+ double landed_error;
+ double landed_time_error;
+
+ if (!ao_test_main_height_time) {
+ ao_test_main_height_time = ao_test_max_height_time;
+ ao_test_main_height = ao_test_max_height;
+ }
+ drogue_error = fabs(ao_test_max_height_time - drogue_time);
+ main_error = fabs(ao_test_main_height_time - main_time);
+ landed_error = fabs(ao_test_landed_height - landed_height);
+ landed_time_error = ao_test_landed_time - landed_time;
+ if (drogue_error > emulator_error_max || main_error > emulator_error_max ||
+ landed_time_error > emulator_error_max || landed_error > emulator_height_error_max) {
+ printf ("%s %s\n",
+ emulator_app, emulator_name);
+ printf ("\tApogee error %g\n", drogue_error);
+ printf ("\tMain error %g\n", main_error);
+ printf ("\tLanded height error %g\n", landed_error);
+ printf ("\tLanded time error %g\n", landed_time_error);
+ printf ("\tActual: apogee: %d at %7.2f main: %d at %7.2f landed %7.2f at %7.2f\n",
+ ao_test_max_height, ao_test_max_height_time,
+ ao_test_main_height, ao_test_main_height_time,
+ ao_test_landed_height, ao_test_landed_time);
+ printf ("\tComputed: apogee: %d at %7.2f main: %d at %7.2f landed %7.2f at %7.2f\n",
+ drogue_height, drogue_time, main_height, main_time,
+ landed_height, landed_time);
+ exit (1);
+ }
+ exit(0);
+}
+
+void
+ao_insert(void)
+{
+ double time;
+
+ ao_adc_ring[ao_adc_head] = ao_adc_static;
+ ao_adc_head = ao_adc_ring_next(ao_adc_head);
+ if (ao_flight_state != ao_flight_startup) {
+ double height = ao_pres_to_altitude(ao_adc_static.pres_real) - ao_ground_height;
+ double accel = ((ao_flight_ground_accel - ao_adc_static.accel) * GRAVITY * 2.0) /
+ (ao_config.accel_minus_g - ao_config.accel_plus_g);
+
+ if (!tick_offset)
+ tick_offset = -ao_adc_static.tick;
+ if ((prev_tick - ao_adc_static.tick) > 0x400)
+ tick_offset += 65536;
+ prev_tick = ao_adc_static.tick;
+ time = (double) (ao_adc_static.tick + tick_offset) / 100;
+
+ if (ao_test_max_height < height) {
+ ao_test_max_height = height;
+ ao_test_max_height_time = time;
+ ao_test_landed_height = height;
+ ao_test_landed_time = time;
+ }
+ if (height > ao_config.main_deploy) {
+ ao_test_main_height_time = time;
+ ao_test_main_height = height;
+ }
+
+ if (ao_test_landed_height > height) {
+ ao_test_landed_height = height;
+ ao_test_landed_time = time;
+ }
+
+ if (ao_flight_state == ao_flight_landed && !landed_set) {
+ landed_set = 1;
+ landed_time = time;
+ landed_height = height;
+ }
+
+ if (!ao_summary) {
+ printf("%7.2f height %8.2f accel %8.3f state %-8.8s k_height %8.2f k_speed %8.3f k_accel %8.3f avg_height %5d drogue %4d main %4d error %5d\n",
+ time,
+ height,
+ accel,
+ ao_state_names[ao_flight_state],
+ ao_k_height / 65536.0,
+ ao_k_speed / 65536.0 / 16.0,
+ ao_k_accel / 65536.0 / 16.0,
+ ao_avg_height,
+ drogue_height,
+ main_height,
+ ao_error_h_sq_avg);
+
+// if (ao_flight_state == ao_flight_landed)
+// ao_test_exit();
+ }
+ }
+}
+
+#define AO_MAX_CALLSIGN 8
+#define AO_MAX_VERSION 8
+#define AO_MAX_TELEMETRY 128
+
+struct ao_telemetry_generic {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+ uint8_t payload[27]; /* 5 */
+ /* 32 */
+};
+
+#define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01
+#define AO_TELEMETRY_SENSOR_TELEMINI 0x02
+#define AO_TELEMETRY_SENSOR_TELENANO 0x03
+
+struct ao_telemetry_sensor {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+
+ uint8_t state; /* 5 flight state */
+ int16_t accel; /* 6 accelerometer (TM only) */
+ int16_t pres; /* 8 pressure sensor */
+ int16_t temp; /* 10 temperature sensor */
+ int16_t v_batt; /* 12 battery voltage */
+ int16_t sense_d; /* 14 drogue continuity sense (TM/Tm) */
+ int16_t sense_m; /* 16 main continuity sense (TM/Tm) */
+
+ int16_t acceleration; /* 18 m/s² * 16 */
+ int16_t speed; /* 20 m/s * 16 */
+ int16_t height; /* 22 m */
+
+ int16_t ground_pres; /* 24 average pres on pad */
+ int16_t ground_accel; /* 26 average accel on pad */
+ int16_t accel_plus_g; /* 28 accel calibration at +1g */
+ int16_t accel_minus_g; /* 30 accel calibration at -1g */
+ /* 32 */
+};
+
+#define AO_TELEMETRY_CONFIGURATION 0x04
+
+struct ao_telemetry_configuration {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+
+ uint8_t device; /* 5 device type */
+ uint16_t flight; /* 6 flight number */
+ uint8_t config_major; /* 8 Config major version */
+ uint8_t config_minor; /* 9 Config minor version */
+ uint16_t apogee_delay; /* 10 Apogee deploy delay in seconds */
+ uint16_t main_deploy; /* 12 Main deploy alt in meters */
+ uint16_t flight_log_max; /* 14 Maximum flight log size in kB */
+ char callsign[AO_MAX_CALLSIGN]; /* 16 Radio operator identity */
+ char version[AO_MAX_VERSION]; /* 24 Software version */
+ /* 32 */
+};
+
+#define AO_TELEMETRY_LOCATION 0x05
+
+#define AO_GPS_MODE_NOT_VALID 'N'
+#define AO_GPS_MODE_AUTONOMOUS 'A'
+#define AO_GPS_MODE_DIFFERENTIAL 'D'
+#define AO_GPS_MODE_ESTIMATED 'E'
+#define AO_GPS_MODE_MANUAL 'M'
+#define AO_GPS_MODE_SIMULATED 'S'
+
+struct ao_telemetry_location {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+
+ uint8_t flags; /* 5 Number of sats and other flags */
+ int16_t altitude; /* 6 GPS reported altitude (m) */
+ int32_t latitude; /* 8 latitude (degrees * 10⁷) */
+ int32_t longitude; /* 12 longitude (degrees * 10⁷) */
+ uint8_t year; /* 16 (- 2000) */
+ uint8_t month; /* 17 (1-12) */
+ uint8_t day; /* 18 (1-31) */
+ uint8_t hour; /* 19 (0-23) */
+ uint8_t minute; /* 20 (0-59) */
+ uint8_t second; /* 21 (0-59) */
+ uint8_t pdop; /* 22 (m * 5) */
+ uint8_t hdop; /* 23 (m * 5) */
+ uint8_t vdop; /* 24 (m * 5) */
+ uint8_t mode; /* 25 */
+ uint16_t ground_speed; /* 26 cm/s */
+ int16_t climb_rate; /* 28 cm/s */
+ uint8_t course; /* 30 degrees / 2 */
+ uint8_t unused[1]; /* 31 */
+ /* 32 */
+};
+
+#define AO_TELEMETRY_SATELLITE 0x06
+
+struct ao_telemetry_satellite_info {
+ uint8_t svid;
+ uint8_t c_n_1;
+};
+
+struct ao_telemetry_satellite {
+ uint16_t serial; /* 0 */
+ uint16_t tick; /* 2 */
+ uint8_t type; /* 4 */
+ uint8_t channels; /* 5 number of reported sats */
+
+ struct ao_telemetry_satellite_info sats[12]; /* 6 */
+ uint8_t unused[2]; /* 30 */
+ /* 32 */
+};
+
+union ao_telemetry_all {
+ struct ao_telemetry_generic generic;
+ struct ao_telemetry_sensor sensor;
+ struct ao_telemetry_configuration configuration;
+ struct ao_telemetry_location location;
+ struct ao_telemetry_satellite satellite;
+};
+
+uint16_t
+uint16(uint8_t *bytes, int off)
+{
+ off++;
+ return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8);
+}
+
+int16_t
+int16(uint8_t *bytes, int off)
+{
+ return (int16_t) uint16(bytes, off);
+}
+
+void
+ao_sleep(void *wchan)
+{
+ if (wchan == &ao_adc_head) {
+ char type;
+ uint16_t tick;
+ uint16_t a, b;
+ int ret;
+ uint8_t bytes[1024];
+ union ao_telemetry_all telem;
+ char line[1024];
+ char *saveptr;
+ char *l;
+ char *words[64];
+ int nword;
+
+ for (;;) {
+ if (ao_records_read > 2 && ao_flight_state == ao_flight_startup)
+ {
+ ao_adc_static.accel = ao_flight_ground_accel;
+ ao_insert();
+ return;
+ }
+
+ if (!fgets(line, sizeof (line), emulator_in)) {
+ if (++ao_eof_read >= 1000) {
+ if (!ao_summary)
+ printf ("no more data, exiting simulation\n");
+ ao_test_exit();
+ }
+ ao_adc_static.tick += 10;
+ ao_insert();
+ return;
+ }
+ l = line;
+ for (nword = 0; nword < 64; nword++) {
+ words[nword] = strtok_r(l, " \t\n", &saveptr);
+ l = NULL;
+ if (words[nword] == NULL)
+ break;
+ }
+ if (nword == 4) {
+ type = words[0][0];
+ tick = strtoul(words[1], NULL, 16);
+ a = strtoul(words[2], NULL, 16);
+ b = strtoul(words[3], NULL, 16);
+ if (type == 'P')
+ type = 'A';
+ } else if (nword >= 6 && strcmp(words[0], "Accel") == 0) {
+ ao_config.accel_plus_g = atoi(words[3]);
+ ao_config.accel_minus_g = atoi(words[5]);
+ } else if (nword >= 4 && strcmp(words[0], "Main") == 0) {
+ ao_config.main_deploy = atoi(words[2]);
+ } else if (nword >= 36 && strcmp(words[0], "CALL") == 0) {
+ tick = atoi(words[10]);
+ if (!ao_flight_started) {
+ type = 'F';
+ a = atoi(words[26]);
+ ao_flight_started = 1;
+ } else {
+ type = 'A';
+ a = atoi(words[12]);
+ b = atoi(words[14]);
+ }
+ } else if (nword == 3 && strcmp(words[0], "BARO") == 0) {
+ tick = strtol(words[1], NULL, 16);
+ a = 16384 - 328;
+ b = strtol(words[2], NULL, 10);
+ type = 'A';
+ if (!ao_flight_started) {
+ ao_flight_ground_accel = 16384 - 328;
+ ao_config.accel_plus_g = 16384 - 328;
+ ao_config.accel_minus_g = 16384 + 328;
+ ao_flight_started = 1;
+ }
+ } else if (nword == 2 && strcmp(words[0], "TELEM") == 0) {
+ char *hex = words[1];
+ char elt[3];
+ int i, len;
+ uint8_t sum;
+
+ len = strlen(hex);
+ if (len > sizeof (bytes) * 2) {
+ len = sizeof (bytes)*2;
+ hex[len] = '\0';
+ }
+ for (i = 0; i < len; i += 2) {
+ elt[0] = hex[i];
+ elt[1] = hex[i+1];
+ elt[2] = '\0';
+ bytes[i/2] = (uint8_t) strtol(elt, NULL, 16);
+ }
+ len = i/2;
+ if (bytes[0] != len - 2) {
+ printf ("bad length %d != %d\n", bytes[0], len - 2);
+ continue;
+ }
+ sum = 0x5a;
+ for (i = 1; i < len-1; i++)
+ sum += bytes[i];
+ if (sum != bytes[len-1]) {
+ printf ("bad checksum\n");
+ continue;
+ }
+ if ((bytes[len-2] & 0x80) == 0) {
+ continue;
+ }
+ if (len == 36) {
+ memcpy(&telem, bytes + 1, 32);
+ tick = telem.generic.tick;
+ switch (telem.generic.type) {
+ case AO_TELEMETRY_SENSOR_TELEMETRUM:
+ case AO_TELEMETRY_SENSOR_TELEMINI:
+ case AO_TELEMETRY_SENSOR_TELENANO:
+ if (!ao_flight_started) {
+ ao_flight_ground_accel = telem.sensor.ground_accel;
+ ao_config.accel_plus_g = telem.sensor.accel_plus_g;
+ ao_config.accel_minus_g = telem.sensor.accel_minus_g;
+ ao_flight_started = 1;
+ }
+ type = 'A';
+ a = telem.sensor.accel;
+ b = telem.sensor.pres;
+ break;
+ }
+ } else if (len == 99) {
+ ao_flight_started = 1;
+ tick = uint16(bytes, 21);
+ ao_flight_ground_accel = int16(bytes, 7);
+ ao_config.accel_plus_g = int16(bytes, 17);
+ ao_config.accel_minus_g = int16(bytes, 19);
+ type = 'A';
+ a = int16(bytes, 23);
+ b = int16(bytes, 25);
+ } else if (len == 98) {
+ ao_flight_started = 1;
+ tick = uint16(bytes, 20);
+ ao_flight_ground_accel = int16(bytes, 6);
+ ao_config.accel_plus_g = int16(bytes, 16);
+ ao_config.accel_minus_g = int16(bytes, 18);
+ type = 'A';
+ a = int16(bytes, 22);
+ b = int16(bytes, 24);
+ } else {
+ printf("unknown len %d\n", len);
+ continue;
+ }
+ }
+ if (type != 'F' && !ao_flight_started)
+ continue;
+
+ switch (type) {
+ case 'F':
+ ao_flight_ground_accel = a;
+ if (ao_config.accel_plus_g == 0) {
+ ao_config.accel_plus_g = a;
+ ao_config.accel_minus_g = a + 530;
+ }
+ if (ao_config.main_deploy == 0)
+ ao_config.main_deploy = 250;
+ ao_flight_started = 1;
+ break;
+ case 'S':
+ break;
+ case 'A':
+ ao_adc_static.tick = tick;
+ ao_adc_static.accel = a;
+ ao_adc_static.pres_real = b;
+ if (b < AO_MIN_BARO_VALUE)
+ b = AO_MIN_BARO_VALUE;
+ ao_adc_static.pres = b;
+ ao_records_read++;
+ ao_insert();
+ return;
+ case 'T':
+ ao_adc_static.tick = tick;
+ ao_adc_static.temp = a;
+ ao_adc_static.v_batt = b;
+ break;
+ case 'D':
+ case 'G':
+ case 'N':
+ case 'W':
+ case 'H':
+ break;
+ }
+ }
+
+ }
+}
+#define COUNTS_PER_G 264.8
+
+void
+ao_dump_state(void)
+{
+}
+
+static const struct option options[] = {
+ { .name = "summary", .has_arg = 0, .val = 's' },
+ { .name = "debug", .has_arg = 0, .val = 'd' },
+ { 0, 0, 0, 0},
+};
+
+void run_flight_fixed(char *name, FILE *f, int summary)
+{
+ emulator_name = name;
+ emulator_in = f;
+ ao_summary = summary;
+ ao_flight_init();
+ ao_flight();
+}
+
+int
+main (int argc, char **argv)
+{
+ int summary = 0;
+ int c;
+ int i;
+
+#if HAS_ACCEL
+ emulator_app="full";
+#else
+ emulator_app="baro";
+#endif
+ while ((c = getopt_long(argc, argv, "sd", options, NULL)) != -1) {
+ switch (c) {
+ case 's':
+ summary = 1;
+ break;
+ case 'd':
+ ao_flight_debug = 1;
+ break;
+ }
+ }
+
+ if (optind == argc)
+ run_flight_fixed("<stdin>", stdin, summary);
+ else
+ for (i = optind; i < argc; i++) {
+ FILE *f = fopen(argv[i], "r");
+ if (!f) {
+ perror(argv[i]);
+ continue;
+ }
+ run_flight_fixed(argv[i], f, summary);
+ fclose(f);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#define AO_GPS_TEST
+#include "ao_host.h"
+#include <termios.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#define AO_GPS_NUM_SAT_MASK (0xf << 0)
+#define AO_GPS_NUM_SAT_SHIFT (0)
+
+#define AO_GPS_VALID (1 << 4)
+#define AO_GPS_RUNNING (1 << 5)
+#define AO_GPS_DATE_VALID (1 << 6)
+#define AO_GPS_COURSE_VALID (1 << 7)
+
+struct ao_gps_orig {
+ uint8_t year;
+ uint8_t month;
+ uint8_t day;
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
+ uint8_t flags;
+ int32_t latitude; /* degrees * 10⁷ */
+ int32_t longitude; /* degrees * 10⁷ */
+ int16_t altitude; /* m */
+ uint16_t ground_speed; /* cm/s */
+ uint8_t course; /* degrees / 2 */
+ uint8_t hdop; /* * 5 */
+ int16_t climb_rate; /* cm/s */
+ uint16_t h_error; /* m */
+ uint16_t v_error; /* m */
+};
+
+#define SIRF_SAT_STATE_ACQUIRED (1 << 0)
+#define SIRF_SAT_STATE_CARRIER_PHASE_VALID (1 << 1)
+#define SIRF_SAT_BIT_SYNC_COMPLETE (1 << 2)
+#define SIRF_SAT_SUBFRAME_SYNC_COMPLETE (1 << 3)
+#define SIRF_SAT_CARRIER_PULLIN_COMPLETE (1 << 4)
+#define SIRF_SAT_CODE_LOCKED (1 << 5)
+#define SIRF_SAT_ACQUISITION_FAILED (1 << 6)
+#define SIRF_SAT_EPHEMERIS_AVAILABLE (1 << 7)
+
+struct ao_gps_sat_orig {
+ uint8_t svid;
+ uint8_t c_n_1;
+};
+
+#define AO_MAX_GPS_TRACKING 12
+
+struct ao_gps_tracking_orig {
+ uint8_t channels;
+ struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING];
+};
+
+#define ao_telemetry_location ao_gps_orig
+#define ao_telemetry_satellite ao_gps_tracking_orig
+#define ao_telemetry_satellite_info ao_gps_sat_orig
+
+void
+ao_mutex_get(uint8_t *mutex)
+{
+}
+
+void
+ao_mutex_put(uint8_t *mutex)
+{
+}
+
+static int
+ao_gps_fd;
+
+static void
+ao_dbg_char(char c)
+{
+ char line[128];
+ line[0] = '\0';
+ if (c < ' ') {
+ if (c == '\n')
+ sprintf (line, "\n");
+ else
+ sprintf (line, "\\%02x", ((int) c) & 0xff);
+ } else {
+ sprintf (line, "%c", c);
+ }
+ write(1, line, strlen(line));
+}
+
+#define QUEUE_LEN 4096
+
+static char input_queue[QUEUE_LEN];
+int input_head, input_tail;
+
+#include <sys/time.h>
+
+int
+get_millis(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
+
+static void
+check_sirf_message(char *from, uint8_t *msg, int len)
+{
+ uint16_t encoded_len, encoded_cksum;
+ uint16_t cksum;
+ uint8_t id;
+ int i;
+
+ if (msg[0] != 0xa0 || msg[1] != 0xa2) {
+ printf ("bad header\n");
+ return;
+ }
+ if (len < 7) {
+ printf("short\n");
+ return;
+ }
+ if (msg[len-1] != 0xb3 || msg[len-2] != 0xb0) {
+ printf ("bad trailer\n");
+ return;
+ }
+ encoded_len = (msg[2] << 8) | msg[3];
+ id = msg[4];
+/* printf ("%9d: %3d\n", get_millis(), id); */
+ if (encoded_len != len - 8) {
+ if (id != 52)
+ printf ("length mismatch (got %d, wanted %d)\n",
+ len - 8, encoded_len);
+ return;
+ }
+ encoded_cksum = (msg[len - 4] << 8) | msg[len-3];
+ cksum = 0;
+ for (i = 4; i < len - 4; i++)
+ cksum = (cksum + msg[i]) & 0x7fff;
+ if (encoded_cksum != cksum) {
+ printf ("cksum mismatch (got %04x wanted %04x)\n",
+ cksum, encoded_cksum);
+ return;
+ }
+ id = msg[4];
+ switch (id) {
+ case 41:{
+ int off = 4;
+
+ uint8_t id;
+ uint16_t nav_valid;
+ uint16_t nav_type;
+ uint16_t week;
+ uint32_t tow;
+ uint16_t year;
+ uint8_t month;
+ uint8_t day;
+ uint8_t hour;
+ uint8_t minute;
+ uint16_t second;
+ uint32_t sat_list;
+ int32_t lat;
+ int32_t lon;
+ int32_t alt_ell;
+ int32_t alt_msl;
+ int8_t datum;
+ uint16_t sog;
+ uint16_t cog;
+ int16_t mag_var;
+ int16_t climb_rate;
+ int16_t heading_rate;
+ uint32_t h_error;
+ uint32_t v_error;
+ uint32_t t_error;
+ uint16_t h_v_error;
+
+#define get_u8(u) u = (msg[off]); off+= 1
+#define get_u16(u) u = (msg[off] << 8) | (msg[off + 1]); off+= 2
+#define get_u32(u) u = (msg[off] << 24) | (msg[off + 1] << 16) | (msg[off+2] << 8) | (msg[off+3]); off+= 4
+
+ get_u8(id);
+ get_u16(nav_valid);
+ get_u16(nav_type);
+ get_u16(week);
+ get_u32(tow);
+ get_u16(year);
+ get_u8(month);
+ get_u8(day);
+ get_u8(hour);
+ get_u8(minute);
+ get_u16(second);
+ get_u32(sat_list);
+ get_u32(lat);
+ get_u32(lon);
+ get_u32(alt_ell);
+ get_u32(alt_msl);
+ get_u8(datum);
+ get_u16(sog);
+ get_u16(cog);
+ get_u16(mag_var);
+ get_u16(climb_rate);
+ get_u16(heading_rate);
+ get_u32(h_error);
+ get_u32(v_error);
+ get_u32(t_error);
+ get_u16(h_v_error);
+
+
+ printf ("Geodetic Navigation Data (41):\n");
+ printf ("\tNav valid %04x\n", nav_valid);
+ printf ("\tNav type %04x\n", nav_type);
+ printf ("\tWeek %5d", week);
+ printf (" TOW %9d", tow);
+ printf (" %4d-%2d-%2d %02d:%02d:%07.4f\n",
+ year, month, day,
+ hour, minute, second / 1000.0);
+ printf ("\tsats: %08x\n", sat_list);
+ printf ("\tlat: %g", lat / 1.0e7);
+ printf (" lon: %g", lon / 1.0e7);
+ printf (" alt_ell: %g", alt_ell / 100.0);
+ printf (" alt_msll: %g", alt_msl / 100.0);
+ printf (" datum: %d\n", datum);
+ printf ("\tground speed: %g", sog / 100.0);
+ printf (" course: %g", cog / 100.0);
+ printf (" climb: %g", climb_rate / 100.0);
+ printf (" heading rate: %g\n", heading_rate / 100.0);
+ printf ("\th error: %g", h_error / 100.0);
+ printf (" v error: %g", v_error / 100.0);
+ printf (" t error: %g", t_error / 100.0);
+ printf (" h vel error: %g\n", h_v_error / 100.0);
+ break;
+ }
+ case 4: {
+ int off = 4;
+ uint8_t id;
+ int16_t gps_week;
+ uint32_t gps_tow;
+ uint8_t channels;
+ int j, k;
+
+ get_u8(id);
+ get_u16(gps_week);
+ get_u32(gps_tow);
+ get_u8(channels);
+
+ printf ("Measured Tracker Data (4):\n");
+ printf ("GPS week: %d\n", gps_week);
+ printf ("GPS time of week: %d\n", gps_tow);
+ printf ("channels: %d\n", channels);
+ for (j = 0; j < 12; j++) {
+ uint8_t svid, azimuth, elevation;
+ uint16_t state;
+ uint8_t c_n[10];
+ get_u8(svid);
+ get_u8(azimuth);
+ get_u8(elevation);
+ get_u16(state);
+ for (k = 0; k < 10; k++) {
+ get_u8(c_n[k]);
+ }
+ printf ("Sat %3d:", svid);
+ printf (" aziumuth: %6.1f", azimuth * 1.5);
+ printf (" elevation: %6.1f", elevation * 0.5);
+ printf (" state: 0x%02x", state);
+ printf (" c_n:");
+ for (k = 0; k < 10; k++)
+ printf(" %3d", c_n[k]);
+ if (state & SIRF_SAT_STATE_ACQUIRED)
+ printf(" acq,");
+ if (state & SIRF_SAT_STATE_CARRIER_PHASE_VALID)
+ printf(" car,");
+ if (state & SIRF_SAT_BIT_SYNC_COMPLETE)
+ printf(" bit,");
+ if (state & SIRF_SAT_SUBFRAME_SYNC_COMPLETE)
+ printf(" sub,");
+ if (state & SIRF_SAT_CARRIER_PULLIN_COMPLETE)
+ printf(" pullin,");
+ if (state & SIRF_SAT_CODE_LOCKED)
+ printf(" code,");
+ if (state & SIRF_SAT_ACQUISITION_FAILED)
+ printf(" fail,");
+ if (state & SIRF_SAT_EPHEMERIS_AVAILABLE)
+ printf(" ephem,");
+ printf ("\n");
+ }
+ break;
+ }
+ default:
+ return;
+ printf ("%s %4d:", from, encoded_len);
+ for (i = 4; i < len - 4; i++) {
+ if (((i - 4) & 0xf) == 0)
+ printf("\n ");
+ printf (" %3d", msg[i]);
+ }
+ printf ("\n");
+ }
+}
+
+static uint8_t sirf_message[4096];
+static int sirf_message_len;
+static uint8_t sirf_in_message[4096];
+static int sirf_in_len;
+
+char
+ao_serial_getchar(void)
+{
+ char c;
+ uint8_t uc;
+
+ while (input_head == input_tail) {
+ for (;;) {
+ input_tail = read(ao_gps_fd, input_queue, QUEUE_LEN);
+ if (input_tail < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ perror ("getchar");
+ exit (1);
+ }
+ input_head = 0;
+ break;
+ }
+ }
+ c = input_queue[input_head];
+ input_head = (input_head + 1) % QUEUE_LEN;
+ uc = c;
+ if (sirf_in_len || uc == 0xa0) {
+ if (sirf_in_len < 4096)
+ sirf_in_message[sirf_in_len++] = uc;
+ if (uc == 0xb3) {
+ check_sirf_message("recv", sirf_in_message, sirf_in_len);
+ sirf_in_len = 0;
+ }
+ }
+ return c;
+}
+
+
+void
+ao_serial_putchar(char c)
+{
+ int i;
+ uint8_t uc = (uint8_t) c;
+
+ if (sirf_message_len || uc == 0xa0) {
+ if (sirf_message_len < 4096)
+ sirf_message[sirf_message_len++] = uc;
+ if (uc == 0xb3) {
+ check_sirf_message("send", sirf_message, sirf_message_len);
+ sirf_message_len = 0;
+ }
+ }
+ for (;;) {
+ i = write(ao_gps_fd, &c, 1);
+ if (i == 1) {
+ if ((uint8_t) c == 0xb3 || c == '\r') {
+ static const struct timespec delay = {
+ .tv_sec = 0,
+ .tv_nsec = 100 * 1000 * 1000
+ };
+ tcdrain(ao_gps_fd);
+// nanosleep(&delay, NULL);
+ }
+ break;
+ }
+ if (i < 0 && (errno == EINTR || errno == EAGAIN))
+ continue;
+ perror("putchar");
+ exit(1);
+ }
+}
+
+#define AO_SERIAL_SPEED_4800 0
+#define AO_SERIAL_SPEED_57600 1
+
+static void
+ao_serial_set_speed(uint8_t speed)
+{
+ int fd = ao_gps_fd;
+ struct termios termios;
+
+ tcdrain(fd);
+ tcgetattr(fd, &termios);
+ switch (speed) {
+ case AO_SERIAL_SPEED_4800:
+ cfsetspeed(&termios, B4800);
+ break;
+ case AO_SERIAL_SPEED_57600:
+ cfsetspeed(&termios, B57600);
+ break;
+ }
+ tcsetattr(fd, TCSAFLUSH, &termios);
+ tcflush(fd, TCIFLUSH);
+}
+
+#define ao_time() 0
+
+#include "ao_gps_print.c"
+#include "ao_gps_sirf.c"
+
+void
+ao_dump_state(void *wchan)
+{
+ double lat, lon;
+ int i;
+ if (wchan == &ao_gps_data)
+ ao_gps_print(&ao_gps_data);
+ else
+ ao_gps_tracking_print(&ao_gps_tracking_data);
+ putchar('\n');
+ return;
+ printf ("%02d:%02d:%02d",
+ ao_gps_data.hour, ao_gps_data.minute,
+ ao_gps_data.second);
+ printf (" nsat %d %svalid",
+ ao_gps_data.flags & AO_GPS_NUM_SAT_MASK,
+ ao_gps_data.flags & AO_GPS_VALID ? "" : "not ");
+ printf (" lat %g lon %g alt %d",
+ ao_gps_data.latitude / 1.0e7,
+ ao_gps_data.longitude / 1.0e7,
+ ao_gps_data.altitude);
+ printf (" speed %g climb %g course %d",
+ ao_gps_data.ground_speed / 100.0,
+ ao_gps_data.climb_rate / 100.0,
+ ao_gps_data.course * 2);
+ printf (" hdop %g h_error %d v_error %d",
+ ao_gps_data.hdop / 5.0,
+ ao_gps_data.h_error, ao_gps_data.v_error);
+ printf("\n");
+ printf ("\t");
+ for (i = 0; i < 12; i++)
+ printf (" %2d(%02d)",
+ ao_gps_tracking_data.sats[i].svid,
+ ao_gps_tracking_data.sats[i].c_n_1);
+ printf ("\n");
+}
+
+int
+ao_gps_open(const char *tty)
+{
+ struct termios termios;
+ int fd;
+
+ fd = open (tty, O_RDWR);
+ if (fd < 0)
+ return -1;
+
+ tcgetattr(fd, &termios);
+ cfmakeraw(&termios);
+ cfsetspeed(&termios, B4800);
+ tcsetattr(fd, TCSAFLUSH, &termios);
+
+ tcdrain(fd);
+ tcflush(fd, TCIFLUSH);
+ return fd;
+}
+
+#include <getopt.h>
+
+static const struct option options[] = {
+ { .name = "tty", .has_arg = 1, .val = 'T' },
+ { 0, 0, 0, 0},
+};
+
+static void usage(char *program)
+{
+ fprintf(stderr, "usage: %s [--tty <tty-name>]\n", program);
+ exit(1);
+}
+
+int
+main (int argc, char **argv)
+{
+ char *tty = "/dev/ttyUSB0";
+ int c;
+
+ while ((c = getopt_long(argc, argv, "T:", options, NULL)) != -1) {
+ switch (c) {
+ case 'T':
+ tty = optarg;
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+ ao_gps_fd = ao_gps_open(tty);
+ if (ao_gps_fd < 0) {
+ perror (tty);
+ exit (1);
+ }
+ ao_gps_setup();
+ ao_gps();
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#define AO_GPS_TEST
+#include "ao_host.h"
+#include <termios.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#define AO_GPS_NUM_SAT_MASK (0xf << 0)
+#define AO_GPS_NUM_SAT_SHIFT (0)
+
+#define AO_GPS_VALID (1 << 4)
+#define AO_GPS_RUNNING (1 << 5)
+#define AO_GPS_DATE_VALID (1 << 6)
+#define AO_GPS_COURSE_VALID (1 << 7)
+
+struct ao_gps_orig {
+ uint8_t year;
+ uint8_t month;
+ uint8_t day;
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
+ uint8_t flags;
+ int32_t latitude; /* degrees * 10⁷ */
+ int32_t longitude; /* degrees * 10⁷ */
+ int16_t altitude; /* m */
+ uint16_t ground_speed; /* cm/s */
+ uint8_t course; /* degrees / 2 */
+ uint8_t hdop; /* * 5 */
+ int16_t climb_rate; /* cm/s */
+ uint16_t h_error; /* m */
+ uint16_t v_error; /* m */
+};
+
+#define SIRF_SAT_STATE_ACQUIRED (1 << 0)
+#define SIRF_SAT_STATE_CARRIER_PHASE_VALID (1 << 1)
+#define SIRF_SAT_BIT_SYNC_COMPLETE (1 << 2)
+#define SIRF_SAT_SUBFRAME_SYNC_COMPLETE (1 << 3)
+#define SIRF_SAT_CARRIER_PULLIN_COMPLETE (1 << 4)
+#define SIRF_SAT_CODE_LOCKED (1 << 5)
+#define SIRF_SAT_ACQUISITION_FAILED (1 << 6)
+#define SIRF_SAT_EPHEMERIS_AVAILABLE (1 << 7)
+
+struct ao_gps_sat_orig {
+ uint8_t svid;
+ uint8_t c_n_1;
+};
+
+#define AO_MAX_GPS_TRACKING 12
+
+struct ao_gps_tracking_orig {
+ uint8_t channels;
+ struct ao_gps_sat_orig sats[AO_MAX_GPS_TRACKING];
+};
+
+#define ao_telemetry_location ao_gps_orig
+#define ao_telemetry_satellite ao_gps_tracking_orig
+#define ao_telemetry_satellite_info ao_gps_sat_orig
+
+void
+ao_mutex_get(uint8_t *mutex)
+{
+}
+
+void
+ao_mutex_put(uint8_t *mutex)
+{
+}
+
+static int
+ao_gps_fd;
+
+static void
+ao_dbg_char(char c)
+{
+ char line[128];
+ line[0] = '\0';
+ if (c < ' ') {
+ if (c == '\n')
+ sprintf (line, "\n");
+ else
+ sprintf (line, "\\%02x", ((int) c) & 0xff);
+ } else {
+ sprintf (line, "%c", c);
+ }
+ write(1, line, strlen(line));
+}
+
+#define QUEUE_LEN 4096
+
+static char input_queue[QUEUE_LEN];
+int input_head, input_tail;
+
+#include <sys/time.h>
+
+int
+get_millis(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
+
+static void
+check_skytraq_message(char *from, uint8_t *msg, int len)
+{
+ uint16_t encoded_len, encoded_cksum;
+ uint16_t cksum;
+ uint8_t id;
+ int i;
+
+// fwrite(msg, 1, len, stdout);
+ return;
+ if (msg[0] != 0xa0 || msg[1] != 0xa2) {
+ printf ("bad header\n");
+ return;
+ }
+ if (len < 7) {
+ printf("short\n");
+ return;
+ }
+ if (msg[len-1] != 0xb3 || msg[len-2] != 0xb0) {
+ printf ("bad trailer\n");
+ return;
+ }
+ encoded_len = (msg[2] << 8) | msg[3];
+ id = msg[4];
+/* printf ("%9d: %3d\n", get_millis(), id); */
+ if (encoded_len != len - 8) {
+ if (id != 52)
+ printf ("length mismatch (got %d, wanted %d)\n",
+ len - 8, encoded_len);
+ return;
+ }
+ encoded_cksum = (msg[len - 4] << 8) | msg[len-3];
+ cksum = 0;
+ for (i = 4; i < len - 4; i++)
+ cksum = (cksum + msg[i]) & 0x7fff;
+ if (encoded_cksum != cksum) {
+ printf ("cksum mismatch (got %04x wanted %04x)\n",
+ cksum, encoded_cksum);
+ return;
+ }
+ id = msg[4];
+ switch (id) {
+ case 41:{
+ int off = 4;
+
+ uint8_t id;
+ uint16_t nav_valid;
+ uint16_t nav_type;
+ uint16_t week;
+ uint32_t tow;
+ uint16_t year;
+ uint8_t month;
+ uint8_t day;
+ uint8_t hour;
+ uint8_t minute;
+ uint16_t second;
+ uint32_t sat_list;
+ int32_t lat;
+ int32_t lon;
+ int32_t alt_ell;
+ int32_t alt_msl;
+ int8_t datum;
+ uint16_t sog;
+ uint16_t cog;
+ int16_t mag_var;
+ int16_t climb_rate;
+ int16_t heading_rate;
+ uint32_t h_error;
+ uint32_t v_error;
+ uint32_t t_error;
+ uint16_t h_v_error;
+
+#define get_u8(u) u = (msg[off]); off+= 1
+#define get_u16(u) u = (msg[off] << 8) | (msg[off + 1]); off+= 2
+#define get_u32(u) u = (msg[off] << 24) | (msg[off + 1] << 16) | (msg[off+2] << 8) | (msg[off+3]); off+= 4
+
+ get_u8(id);
+ get_u16(nav_valid);
+ get_u16(nav_type);
+ get_u16(week);
+ get_u32(tow);
+ get_u16(year);
+ get_u8(month);
+ get_u8(day);
+ get_u8(hour);
+ get_u8(minute);
+ get_u16(second);
+ get_u32(sat_list);
+ get_u32(lat);
+ get_u32(lon);
+ get_u32(alt_ell);
+ get_u32(alt_msl);
+ get_u8(datum);
+ get_u16(sog);
+ get_u16(cog);
+ get_u16(mag_var);
+ get_u16(climb_rate);
+ get_u16(heading_rate);
+ get_u32(h_error);
+ get_u32(v_error);
+ get_u32(t_error);
+ get_u16(h_v_error);
+
+
+ printf ("Geodetic Navigation Data (41):\n");
+ printf ("\tNav valid %04x\n", nav_valid);
+ printf ("\tNav type %04x\n", nav_type);
+ printf ("\tWeek %5d", week);
+ printf (" TOW %9d", tow);
+ printf (" %4d-%2d-%2d %02d:%02d:%07.4f\n",
+ year, month, day,
+ hour, minute, second / 1000.0);
+ printf ("\tsats: %08x\n", sat_list);
+ printf ("\tlat: %g", lat / 1.0e7);
+ printf (" lon: %g", lon / 1.0e7);
+ printf (" alt_ell: %g", alt_ell / 100.0);
+ printf (" alt_msll: %g", alt_msl / 100.0);
+ printf (" datum: %d\n", datum);
+ printf ("\tground speed: %g", sog / 100.0);
+ printf (" course: %g", cog / 100.0);
+ printf (" climb: %g", climb_rate / 100.0);
+ printf (" heading rate: %g\n", heading_rate / 100.0);
+ printf ("\th error: %g", h_error / 100.0);
+ printf (" v error: %g", v_error / 100.0);
+ printf (" t error: %g", t_error / 100.0);
+ printf (" h vel error: %g\n", h_v_error / 100.0);
+ break;
+ }
+ case 4: {
+ int off = 4;
+ uint8_t id;
+ int16_t gps_week;
+ uint32_t gps_tow;
+ uint8_t channels;
+ int j, k;
+
+ get_u8(id);
+ get_u16(gps_week);
+ get_u32(gps_tow);
+ get_u8(channels);
+
+ printf ("Measured Tracker Data (4):\n");
+ printf ("GPS week: %d\n", gps_week);
+ printf ("GPS time of week: %d\n", gps_tow);
+ printf ("channels: %d\n", channels);
+ for (j = 0; j < 12; j++) {
+ uint8_t svid, azimuth, elevation;
+ uint16_t state;
+ uint8_t c_n[10];
+ get_u8(svid);
+ get_u8(azimuth);
+ get_u8(elevation);
+ get_u16(state);
+ for (k = 0; k < 10; k++) {
+ get_u8(c_n[k]);
+ }
+ printf ("Sat %3d:", svid);
+ printf (" aziumuth: %6.1f", azimuth * 1.5);
+ printf (" elevation: %6.1f", elevation * 0.5);
+ printf (" state: 0x%02x", state);
+ printf (" c_n:");
+ for (k = 0; k < 10; k++)
+ printf(" %3d", c_n[k]);
+ if (state & SIRF_SAT_STATE_ACQUIRED)
+ printf(" acq,");
+ if (state & SIRF_SAT_STATE_CARRIER_PHASE_VALID)
+ printf(" car,");
+ if (state & SIRF_SAT_BIT_SYNC_COMPLETE)
+ printf(" bit,");
+ if (state & SIRF_SAT_SUBFRAME_SYNC_COMPLETE)
+ printf(" sub,");
+ if (state & SIRF_SAT_CARRIER_PULLIN_COMPLETE)
+ printf(" pullin,");
+ if (state & SIRF_SAT_CODE_LOCKED)
+ printf(" code,");
+ if (state & SIRF_SAT_ACQUISITION_FAILED)
+ printf(" fail,");
+ if (state & SIRF_SAT_EPHEMERIS_AVAILABLE)
+ printf(" ephem,");
+ printf ("\n");
+ }
+ break;
+ }
+ default:
+ return;
+ printf ("%s %4d:", from, encoded_len);
+ for (i = 4; i < len - 4; i++) {
+ if (((i - 4) & 0xf) == 0)
+ printf("\n ");
+ printf (" %3d", msg[i]);
+ }
+ printf ("\n");
+ }
+}
+
+static uint8_t skytraq_message[4096];
+static int skytraq_message_len;
+static uint8_t skytraq_in_message[4096];
+static int skytraq_in_len;
+
+char
+ao_serial_getchar(void)
+{
+ char c;
+ uint8_t uc;
+
+ while (input_head == input_tail) {
+ for (;;) {
+ input_tail = read(ao_gps_fd, input_queue, QUEUE_LEN);
+ if (input_tail < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ perror ("getchar");
+ exit (1);
+ }
+ input_head = 0;
+ break;
+ }
+ }
+ c = input_queue[input_head];
+ input_head = (input_head + 1) % QUEUE_LEN;
+ uc = c;
+// printf ("c: %02x %c\n", uc, uc);
+ if (skytraq_in_len || uc == '$') {
+ if (skytraq_in_len < 4096)
+ skytraq_in_message[skytraq_in_len++] = uc;
+ if (uc == 0x0a) {
+ check_skytraq_message("recv", skytraq_in_message, skytraq_in_len);
+ skytraq_in_len = 0;
+ }
+ }
+ return c;
+}
+
+
+void
+ao_serial_putchar(char c)
+{
+ int i;
+ uint8_t uc = (uint8_t) c;
+
+ if (skytraq_message_len || uc == 0xa0) {
+ if (skytraq_message_len < 4096)
+ skytraq_message[skytraq_message_len++] = uc;
+ if (uc == 0x0a) {
+ check_skytraq_message("send", skytraq_message, skytraq_message_len);
+ skytraq_message_len = 0;
+ }
+ }
+ for (;;) {
+ i = write(ao_gps_fd, &c, 1);
+ if (i == 1) {
+ if ((uint8_t) c == 0xb3 || c == '\r') {
+ static const struct timespec delay = {
+ .tv_sec = 0,
+ .tv_nsec = 100 * 1000 * 1000
+ };
+ tcdrain(ao_gps_fd);
+// nanosleep(&delay, NULL);
+ }
+ break;
+ }
+ if (i < 0 && (errno == EINTR || errno == EAGAIN))
+ continue;
+ perror("putchar");
+ exit(1);
+ }
+}
+
+#define AO_SERIAL_SPEED_4800 0
+#define AO_SERIAL_SPEED_9600 1
+#define AO_SERIAL_SPEED_57600 2
+
+static void
+ao_serial_set_speed(uint8_t speed)
+{
+ int fd = ao_gps_fd;
+ struct termios termios;
+
+ tcdrain(fd);
+ tcgetattr(fd, &termios);
+ switch (speed) {
+ case AO_SERIAL_SPEED_4800:
+ cfsetspeed(&termios, B4800);
+ break;
+ case AO_SERIAL_SPEED_9600:
+ cfsetspeed(&termios, B38400);
+ break;
+ case AO_SERIAL_SPEED_57600:
+ cfsetspeed(&termios, B57600);
+ break;
+ }
+ tcsetattr(fd, TCSAFLUSH, &termios);
+ tcflush(fd, TCIFLUSH);
+}
+
+#define ao_time() 0
+
+#include "ao_gps_print.c"
+#include "ao_gps_skytraq.c"
+
+void
+ao_dump_state(void *wchan)
+{
+ double lat, lon;
+ int i;
+ if (wchan == &ao_gps_data)
+ ao_gps_print(&ao_gps_data);
+ else
+ ao_gps_tracking_print(&ao_gps_tracking_data);
+ putchar('\n');
+ return;
+}
+
+int
+ao_gps_open(const char *tty)
+{
+ struct termios termios;
+ int fd;
+
+ fd = open (tty, O_RDWR);
+ if (fd < 0)
+ return -1;
+
+ tcgetattr(fd, &termios);
+ cfmakeraw(&termios);
+ cfsetspeed(&termios, B4800);
+ tcsetattr(fd, TCSAFLUSH, &termios);
+
+ tcdrain(fd);
+ tcflush(fd, TCIFLUSH);
+ return fd;
+}
+
+#include <getopt.h>
+
+static const struct option options[] = {
+ { .name = "tty", .has_arg = 1, .val = 'T' },
+ { 0, 0, 0, 0},
+};
+
+static void usage(char *program)
+{
+ fprintf(stderr, "usage: %s [--tty <tty-name>]\n", program);
+ exit(1);
+}
+
+int
+main (int argc, char **argv)
+{
+ char *tty = "/dev/ttyUSB0";
+ int c;
+
+ while ((c = getopt_long(argc, argv, "T:", options, NULL)) != -1) {
+ switch (c) {
+ case 'T':
+ tty = optarg;
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+ ao_gps_fd = ao_gps_open(tty);
+ if (ao_gps_fd < 0) {
+ perror (tty);
+ exit (1);
+ }
+ ao_gps();
+}
-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:
+
+++ /dev/null
-PROG = tidongle-$(VERSION).ihx
-
-SRC = \
- $(TI_SRC)
-
-PRODUCT=TIDongle
-
-PRODUCT_DEF=-DTIDONGLE
-IDPRODUCT=0x000a
--- /dev/null
+#!/bin/sh
+
+autoimport ParseArgs;
+
+void
+write_ucs2(string a, string description)
+{
+ int len = String::length(a);
+
+ printf("/* %s */\n", description);
+ printf("#define AO_%s_LEN 0x%02x\n", description, len * 2 + 2);
+ printf("#define AO_%s_STRING \"%s\"\n", description, a);
+ printf("#define AO_%s_UCS2", description);
+ for (int i = 0; i < len; i++) {
+ int c = a[i];
+ if (i > 0)
+ printf(",");
+ if (0x20 <= c && c < 128)
+ printf(" '%c', 0", c);
+ else
+ printf(" LE_WORD(0x%04x),", c);
+ }
+ printf("\n\n");
+}
+
+void
+write_string(string a, string description)
+{
+ printf ("/* %s */\n", description);
+ printf ("#define AO_%s_STRING \"%s\"\n", description, a);
+}
+
+void
+write_int(int a, string description)
+{
+ printf ("/* %s */\n", description);
+ printf ("#define AO_%s_NUMBER %d\n\n", description, a);
+}
+
+void
+write_hex(int a, string description)
+{
+ printf ("/* %s */\n", description);
+ printf ("#define AO_%s_NUMBER 0x%04x\n\n", description, a);
+}
+
+string manufacturer = "altusmetrum.org";
+string product = "TeleMetrum";
+string version = "0.0";
+int serial = 1;
+int user_argind = 0;
+int id_product = 0x000a;
+
+argdesc argd = {
+ .args = {
+ {
+ .var = { .arg_string = &manufacturer },
+ .abbr = 'm',
+ .name = "manufacturer",
+ .expr_name = "manf",
+ .desc = "Manufacturer name." },
+ {
+ .var = { .arg_string = &product },
+ .abbr = 'p',
+ .name = "product",
+ .expr_name = "prod",
+ .desc = "Product name." },
+ {
+ .var = { .arg_int = &id_product },
+ .abbr = 'i',
+ .name = "id_product",
+ .expr_name = "id_p",
+ .desc = "Product ID." },
+ {
+ .var = { .arg_int = &serial },
+ .abbr = 's',
+ .name = "serial",
+ .expr_name = "number",
+ .desc = "Serial number." },
+ {
+ .var = { .arg_string = &version },
+ .abbr = 'v',
+ .name = "version",
+ .expr_name = "string",
+ .desc = "Program version." },
+ },
+ .prog_name = "usb descriptors",
+};
+
+void
+main()
+{
+ string[dim(argv)-1] nargv = {[n] = argv[n+1]};
+ parseargs(&argd, &nargv);
+ write_ucs2(manufacturer, "iManufacturer");
+ write_ucs2(product, "iProduct");
+ write_ucs2(sprintf("%06d", serial), "iSerial");
+ write_int(serial, "iSerial");
+ write_hex(id_product, "idProduct");
+ write_string(version, "iVersion");
+}
+
+main();
--- /dev/null
+#!/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); }'
--- /dev/null
+#!/bin/sh
+HEADER=$1
+MEM=$2
+
+HEADER_STACK=`awk '/#define AO_STACK_START/ {print strtonum($3)}' $HEADER`
+MEM_STACK=`awk '/Stack starts at/ {print strtonum ($4)}' $MEM`
+
+if [ "$HEADER_STACK" -lt "$MEM_STACK" ]; then
+ echo $MEM_STACK | awk '{ printf ("Set AO_STACK_START to at least 0x%x\n", $1); }'
+ exit 1
+else
+ exit 0
+fi
--- /dev/null
+#!/usr/bin/env nickle
+
+int checksum(string a)
+{
+ int c = 0;
+ for (int i = 0; i < String::length(a); i++)
+ c ^= a[i];
+ return c;
+}
+
+void main()
+{
+ for (int i = 1; i < dim(argv); i++)
+ printf ("$%s*%02x\n", argv[i], checksum(argv[i]));
+}
+
+main();
--- /dev/null
+#!/usr/bin/nickle -f
+/*
+ * Pressure Sensor Model, version 1.1
+ *
+ * written by Holly Grimes
+ *
+ * Uses the International Standard Atmosphere as described in
+ * "A Quick Derivation relating altitude to air pressure" (version 1.03)
+ * from the Portland State Aerospace Society, except that the atmosphere
+ * is divided into layers with each layer having a different lapse rate.
+ *
+ * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007
+ * at site <http://en.wikipedia.org/wiki/International_Standard_Atmosphere
+ *
+ * Height measurements use the local tangent plane. The postive z-direction is up.
+ *
+ * All measurements are given in SI units (Kelvin, Pascal, meter, meters/second^2).
+ * The lapse rate is given in Kelvin/meter, the gas constant for air is given
+ * in Joules/(kilogram-Kelvin).
+ */
+
+const real GRAVITATIONAL_ACCELERATION = -9.80665;
+const real AIR_GAS_CONSTANT = 287.053;
+const int NUMBER_OF_LAYERS = 7;
+const real MAXIMUM_ALTITUDE = 84852;
+const real MINIMUM_PRESSURE = 0.3734;
+const real LAYER0_BASE_TEMPERATURE = 288.15;
+const real LAYER0_BASE_PRESSURE = 101325;
+
+/* lapse rate and base altitude for each layer in the atmosphere */
+const real[NUMBER_OF_LAYERS] lapse_rate = {
+ -0.0065, 0.0, 0.001, 0.0028, 0.0, -0.0028, -0.002
+};
+const int[NUMBER_OF_LAYERS] base_altitude = {
+ 0, 11000, 20000, 32000, 47000, 51000, 71000
+};
+
+
+/* outputs atmospheric pressure associated with the given altitude. altitudes
+ are measured with respect to the mean sea level */
+real altitude_to_pressure(real altitude) {
+
+ real base_temperature = LAYER0_BASE_TEMPERATURE;
+ real base_pressure = LAYER0_BASE_PRESSURE;
+
+ real pressure;
+ real base; /* base for function to determine pressure */
+ real exponent; /* exponent for function to determine pressure */
+ int layer_number; /* identifies layer in the atmosphere */
+ int delta_z; /* difference between two altitudes */
+
+ if (altitude > MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */
+ return 0;
+
+ /* calculate the base temperature and pressure for the atmospheric layer
+ associated with the inputted altitude */
+ for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) {
+ delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
+ if (lapse_rate[layer_number] == 0.0) {
+ exponent = GRAVITATIONAL_ACCELERATION * delta_z
+ / AIR_GAS_CONSTANT / base_temperature;
+ base_pressure *= exp(exponent);
+ }
+ else {
+ base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
+ exponent = GRAVITATIONAL_ACCELERATION /
+ (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
+ base_pressure *= pow(base, exponent);
+ }
+ base_temperature += delta_z * lapse_rate[layer_number];
+ }
+
+ /* calculate the pressure at the inputted altitude */
+ delta_z = altitude - base_altitude[layer_number];
+ if (lapse_rate[layer_number] == 0.0) {
+ exponent = GRAVITATIONAL_ACCELERATION * delta_z
+ / AIR_GAS_CONSTANT / base_temperature;
+ pressure = base_pressure * exp(exponent);
+ }
+ else {
+ base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
+ exponent = GRAVITATIONAL_ACCELERATION /
+ (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
+ pressure = base_pressure * pow(base, exponent);
+ }
+
+ return pressure;
+}
+
+
+/* outputs the altitude associated with the given pressure. the altitude
+ returned is measured with respect to the mean sea level */
+real pressure_to_altitude(real pressure) {
+
+ real next_base_temperature = LAYER0_BASE_TEMPERATURE;
+ real next_base_pressure = LAYER0_BASE_PRESSURE;
+
+ real altitude;
+ real base_pressure;
+ real base_temperature;
+ real base; /* base for function to determine base pressure of next layer */
+ real exponent; /* exponent for function to determine base pressure
+ of next layer */
+ real coefficient;
+ int layer_number; /* identifies layer in the atmosphere */
+ int delta_z; /* difference between two altitudes */
+
+ if (pressure < 0) /* illegal pressure */
+ return -1;
+ if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */
+ return MAXIMUM_ALTITUDE;
+
+ /* calculate the base temperature and pressure for the atmospheric layer
+ associated with the inputted pressure. */
+ layer_number = -1;
+ do {
+ layer_number++;
+ base_pressure = next_base_pressure;
+ base_temperature = next_base_temperature;
+ delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
+ if (lapse_rate[layer_number] == 0.0) {
+ exponent = GRAVITATIONAL_ACCELERATION * delta_z
+ / AIR_GAS_CONSTANT / base_temperature;
+ next_base_pressure *= exp(exponent);
+ }
+ else {
+ base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
+ exponent = GRAVITATIONAL_ACCELERATION /
+ (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
+ next_base_pressure *= pow(base, exponent);
+ }
+ next_base_temperature += delta_z * lapse_rate[layer_number];
+ }
+ while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure);
+
+ /* calculate the altitude associated with the inputted pressure */
+ if (lapse_rate[layer_number] == 0.0) {
+ coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION)
+ * base_temperature;
+ altitude = base_altitude[layer_number]
+ + coefficient * log(pressure / base_pressure);
+ }
+ else {
+ base = pressure / base_pressure;
+ exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number]
+ / GRAVITATIONAL_ACCELERATION;
+ coefficient = base_temperature / lapse_rate[layer_number];
+ altitude = base_altitude[layer_number]
+ + coefficient * (pow(base, exponent) - 1);
+ }
+
+ return altitude;
+}
+
+real feet_to_meters(real feet)
+{
+ return feet * (12 * 2.54 / 100);
+}
+
+real meters_to_feet(real meters)
+{
+ return meters / (12 * 2.54 / 100);
+}
+
+/*
+ * Values for our MP3H6115A pressure sensor
+ *
+ * From the data sheet:
+ *
+ * Pressure range: 15-115 kPa
+ * Voltage at 115kPa: 2.82
+ * Output scale: 27mV/kPa
+ *
+ *
+ * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa
+ * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa
+ */
+
+real counts_per_kPa = 27 * 2047 / 3300;
+real counts_at_101_3kPa = 1674;
+
+real fraction_to_kPa(real fraction)
+{
+ return (fraction + 0.095) / 0.009;
+}
+
+
+real count_to_kPa(real count) = fraction_to_kPa(count / 2047);
+
+typedef struct {
+ real m, b;
+ int m_i, b_i;
+} line_t;
+
+line_t best_fit(real[] values, int first, int last) {
+ real sum_x = 0, sum_x2 = 0, sum_y = 0, sum_xy = 0;
+ int n = last - first + 1;
+ real m, b;
+ int m_i, b_i;
+
+ for (int i = first; i <= last; i++) {
+ sum_x += i;
+ sum_x2 += i**2;
+ sum_y += values[i];
+ sum_xy += values[i] * i;
+ }
+ m = (n*sum_xy - sum_y*sum_x) / (n*sum_x2 - sum_x**2);
+ b = sum_y/n - m*(sum_x/n);
+ return (line_t) { m = m, b = b };
+}
+
+real count_to_altitude(real count) {
+ return pressure_to_altitude(count_to_kPa(count) * 1000);
+}
+
+real fraction_to_altitude(real frac) = pressure_to_altitude(fraction_to_kPa(frac) * 1000);
+
+int num_samples = 1024;
+
+real[num_samples] alt = { [n] = fraction_to_altitude(n/(num_samples - 1)) };
+
+int num_part = 128;
+int seg_len = num_samples / num_part;
+
+line_t [dim(alt) / seg_len] fit = {
+ [n] = best_fit(alt, n * seg_len, n * seg_len + seg_len - 1)
+};
+
+int[num_samples/seg_len + 1] alt_part;
+
+alt_part[0] = floor (fit[0].b + 0.5);
+alt_part[dim(fit)] = floor(fit[dim(fit)-1].m * dim(fit) * seg_len + fit[dim(fit)-1].b + 0.5);
+
+for (int i = 0; i < dim(fit) - 1; i++) {
+ real here, there;
+ here = fit[i].m * (i+1) * seg_len + fit[i].b;
+ there = fit[i+1].m * (i+1) * seg_len + fit[i+1].b;
+ alt_part[i+1] = floor ((here + there) / 2 + 0.5);
+}
+
+real count_to_fit_altitude(int count) {
+ int sub = count // seg_len;
+ int off = count % seg_len;
+ line_t l = fit[sub];
+ real r_v;
+ real i_v;
+
+ r_v = count * l.m + l.b;
+ i_v = (alt_part[sub] * (seg_len - off) + alt_part[sub+1] * off) / seg_len;
+ return i_v;
+}
+
+real max_error = 0;
+int max_error_count = 0;
+real total_error = 0;
+
+for (int count = 0; count < num_samples; count++) {
+ real kPa = fraction_to_kPa(count / (num_samples - 1));
+ real meters = pressure_to_altitude(kPa * 1000);
+
+ real meters_approx = count_to_fit_altitude(count);
+ real error = abs(meters - meters_approx);
+
+ total_error += error;
+ if (error > max_error) {
+ max_error = error;
+ max_error_count = count;
+ }
+# printf (" %7d, /* %6.2g kPa %5d count approx %d */\n",
+# floor (meters + 0.5), kPa, count, floor(count_to_fit_altitude(count) + 0.5));
+}
+
+printf ("/*max error %f at %7.3f%%. Average error %f*/\n", max_error, max_error_count / (num_samples - 1) * 100, total_error / num_samples);
+
+printf ("#define NALT %d\n", dim(alt_part));
+printf ("#define ALT_FRAC_BITS %d\n", floor (log2(32768/(dim(alt_part)-1)) + 0.1));
+
+for (int i = 0; i < dim(alt_part); i++) {
+ real fraction = i / (dim(alt_part) - 1);
+ real kPa = fraction_to_kPa(fraction);
+ printf ("%9d, /* %6.2f kPa %7.3f%% */\n",
+ alt_part[i], kPa, fraction * 100);
+}
--- /dev/null
+#!/bin/bash
+
+cd $1 2> /dev/null 1>&2
+
+SIGMA_BOTH="-M 2 -H 6 -A 2"
+SIGMA_BARO="-M 2 -H 6 -A 2"
+SIGMA_ACCEL="-M 2 -H 4 -A 4"
+
+nickle kalman.5c -p AO_BOTH -c both -t 0.01 $SIGMA_BOTH
+nickle kalman.5c -p AO_BOTH -c both -t 0.1 $SIGMA_BOTH
+nickle kalman.5c -p AO_BOTH -c both -t 1 $SIGMA_BOTH
+
+nickle kalman.5c -p AO_ACCEL -c accel -t 0.01 $SIGMA_ACCEL
+nickle kalman.5c -p AO_ACCEL -c accel -t 0.1 $SIGMA_ACCEL
+nickle kalman.5c -p AO_ACCEL -c accel -t 1 $SIGMA_ACCEL
+
+nickle kalman.5c -p AO_BARO -c baro -t 0.01 $SIGMA_BARO
+nickle kalman.5c -p AO_BARO -c baro -t 0.1 $SIGMA_BARO
+nickle kalman.5c -p AO_BARO -c baro -t 1 $SIGMA_BARO
--- /dev/null
+#!/usr/bin/env nickle
+
+int checksum(int[] msg)
+{
+ int sum = 0;
+ for (int i = 0; i < dim(msg); i++) {
+ sum += msg[i];
+ sum &= 0x7fff;
+ }
+ return sum;
+}
+
+void main()
+{
+ string[...] input;
+ int[...] msg;
+
+ setdim(input, 0);
+ while (!File::end(stdin)) {
+ input[dim(input)] = gets();
+ }
+
+ setdim(msg, 0);
+ for (int i = 0; i < dim(input); i++) {
+ string[*] words = String::wordsplit(input[i], " ,\t");
+ for (int j = 0; j < dim(words); j++) {
+ if (words[j] == "/" + "*")
+ break;
+ if (String::length(words[j]) > 0 &&
+ Ctype::isdigit(words[j][0])) {
+ msg[dim(msg)] = string_to_integer(words[j]);
+ }
+ }
+ }
+ printf("\t0xa0, 0xa2, 0x%02x, 0x%02x,\t/* length: %d bytes */\n",
+ dim(msg) >> 8, dim(msg) & 0xff, dim(msg));
+ for (int i = 0; i < dim(input); i++)
+ printf("%s\n", input[i]);
+ int csum = checksum(msg);
+ printf ("\t0x%02x, 0x%02x, 0xb0, 0xb3,\n",
+ csum >> 8, csum & 0xff);
+}
+
+main();
--- /dev/null
+#!/usr/bin/env nickle
+
+int checksum(int[] msg)
+{
+ int sum = 0;
+ for (int i = 0; i < dim(msg); i++) {
+ sum ^= msg[i];
+ sum &= 0xff;
+ }
+ return sum;
+}
+
+void main()
+{
+ string[...] input;
+ int[...] msg;
+
+ setdim(input, 0);
+ while (!File::end(stdin)) {
+ input[dim(input)] = gets();
+ }
+
+ setdim(msg, 0);
+ for (int i = 0; i < dim(input); i++) {
+ string[*] words = String::wordsplit(input[i], " ,\t");
+ for (int j = 0; j < dim(words); j++) {
+ if (words[j] == "/" + "*")
+ break;
+ if (String::length(words[j]) > 0 &&
+ Ctype::isdigit(words[j][0])) {
+ msg[dim(msg)] = string_to_integer(words[j]);
+ }
+ }
+ }
+ printf("\t0xa0, 0xa1, 0x%02x, 0x%02x,\t\t/* length: %d bytes */\n",
+ dim(msg) >> 8, dim(msg) & 0xff, dim(msg));
+ for (int i = 0; i < dim(input); i++)
+ printf("%s\n", input[i]);
+ int csum = checksum(msg);
+ printf ("\t0x%02x, 0x0d, 0x0a,\n",
+ csum);
+}
+
+main();