Merge ccdbg and altos sources into one giant repository
authorKeith Packard <keithp@keithp.com>
Thu, 4 Jun 2009 18:13:15 +0000 (11:13 -0700)
committerKeith Packard <keithp@keithp.com>
Thu, 4 Jun 2009 18:13:15 +0000 (11:13 -0700)
Keeping these separate isn't making things any easier.

Signed-off-by: Keith Packard <keithp@keithp.com>
102 files changed:
.gitignore
COPYING
INSTALL
Makefile.am
README
aoload/aoload.c
aoview/.gitignore [new file with mode: 0644]
aoview/Makefile.am [new file with mode: 0644]
aoview/aoview.glade [new file with mode: 0644]
aoview/aoview.h [new file with mode: 0644]
aoview/aoview_convert.c [new file with mode: 0644]
aoview/aoview_dev.c [new file with mode: 0644]
aoview/aoview_dev_dialog.c [new file with mode: 0644]
aoview/aoview_eeprom.c [new file with mode: 0644]
aoview/aoview_file.c [new file with mode: 0644]
aoview/aoview_log.c [new file with mode: 0644]
aoview/aoview_main.c [new file with mode: 0644]
aoview/aoview_monitor.c [new file with mode: 0644]
aoview/aoview_serial.c [new file with mode: 0644]
aoview/aoview_state.c [new file with mode: 0644]
aoview/aoview_table.c [new file with mode: 0644]
aoview/aoview_util.c [new file with mode: 0644]
aoview/design [new file with mode: 0644]
ccload/ccload.c
ccmanual/ccmanual.c
configure.ac
lib/cc-bitbang.c
lib/cc-usb.c
lib/ccdbg-command.c
lib/ccdbg-flash.c
lib/ccdbg-hex.c
lib/ccdbg-memory.c
lib/ccdbg-rom.c
lib/ccdbg.h
lib/cp-usb-async.c
lib/cp-usb.c
s51/commands
s51/s51-command.c
s51/s51-main.c
s51/s51-parse.c
s51/s51.1
src/25lc1024.h [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/_bp.c [new file with mode: 0644]
src/altitude.h [new file with mode: 0644]
src/ao-make-product.5c [new file with mode: 0644]
src/ao.h [new file with mode: 0644]
src/ao_adc.c [new file with mode: 0644]
src/ao_adc_fake.c [new file with mode: 0644]
src/ao_beep.c [new file with mode: 0644]
src/ao_cmd.c [new file with mode: 0644]
src/ao_config.c [new file with mode: 0644]
src/ao_convert.c [new file with mode: 0644]
src/ao_dbg.c [new file with mode: 0644]
src/ao_dma.c [new file with mode: 0644]
src/ao_ee.c [new file with mode: 0644]
src/ao_ee_fake.c [new file with mode: 0644]
src/ao_flight.c [new file with mode: 0644]
src/ao_flight_test.c [new file with mode: 0644]
src/ao_gps.c [new file with mode: 0644]
src/ao_gps_print.c [new file with mode: 0644]
src/ao_gps_report.c [new file with mode: 0644]
src/ao_ignite.c [new file with mode: 0644]
src/ao_led.c [new file with mode: 0644]
src/ao_log.c [new file with mode: 0644]
src/ao_main.c [new file with mode: 0644]
src/ao_monitor.c [new file with mode: 0644]
src/ao_mutex.c [new file with mode: 0644]
src/ao_panic.c [new file with mode: 0644]
src/ao_product.c [new file with mode: 0644]
src/ao_radio.c [new file with mode: 0644]
src/ao_report.c [new file with mode: 0644]
src/ao_rssi.c [new file with mode: 0644]
src/ao_serial.c [new file with mode: 0644]
src/ao_state.c [new file with mode: 0644]
src/ao_stdio.c [new file with mode: 0644]
src/ao_task.c [new file with mode: 0644]
src/ao_teledongle.c [new file with mode: 0644]
src/ao_telemetrum.c [new file with mode: 0644]
src/ao_telemetry.c [new file with mode: 0644]
src/ao_teleterra.c [new file with mode: 0644]
src/ao_test.c [new file with mode: 0644]
src/ao_tidongle.c [new file with mode: 0644]
src/ao_timer.c [new file with mode: 0644]
src/ao_usb.c [new file with mode: 0644]
src/ao_usb.h [new file with mode: 0644]
src/cc1111.h [new file with mode: 0644]
src/check-stack [new file with mode: 0755]
src/gps-cksum [new file with mode: 0755]
src/make-altitude [new file with mode: 0644]
target/adc-serial/adc_serial.c
target/adc/adc.c
target/beep-timer/beep_timer.c
target/dma/dma.c
target/ee/ee.c
target/isr.c
target/radio/init.c
target/radio/recv.c
target/serial/serial.c
target/timer/cc1111.h
tests/debug_mode
tests/get_status

index 93d05b7f1bd33d995b3a587f2a11bf4183db1823..71b0a61465d5582ccaffe1b0337e5142346567d6 100644 (file)
@@ -1,11 +1,30 @@
-*.o
 *.a
+*.adb
+*.asm
+*.cdb
+*.ihx
+*.lnk
+*.lst
+*.map
+*.mem
+*.o
+*.rel
+*.rst
+*.sym
 .deps
-tags
-Makefile
-Makefile.in
 aclocal.m4
+ao_flight_test
+ao-teledongle.h
+ao-telemetrum.h
+ao-teleterra.h
+ao-tidongle.h
+aoload/aoload
+ccdump/ccdump
+ccmanual/ccmanual
+aoview/Makefile
+aoview/aoview
 autom4te.cache
+config.*
 config.h
 config.h.in
 config.h.in~
@@ -14,7 +33,12 @@ config.status
 configure
 depcomp
 install-sh
+Makefile
 Makefile.in
 missing
 stamp-h1
-
+tags
+teledongle
+telemetrum
+teleterra
+tidongle
diff --git a/COPYING b/COPYING
index d60c31a97a544b53039088d14fe9114583c0efc3..d511905c1647a1e311e8b20d5930a37a9c2531cd 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -1,8 +1,8 @@
                    GNU GENERAL PUBLIC LICENSE
                       Version 2, June 1991
 
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
    59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
@@ -15,7 +15,7 @@ software--to make sure the software is free for all its users.  This
 General Public License applies to most of the Free Software
 Foundation's software and to any other program whose authors commit to
 using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
+the GNU Lesser General Public License instead.)  You can apply it to
 your programs, too.
 
   When we speak of free software, we are referring to freedom, not
@@ -55,7 +55,7 @@ patent must be licensed for everyone's free use or not licensed at all.
 
   The precise terms and conditions for copying, distribution and
 modification follow.
-\f
+
                    GNU GENERAL PUBLIC LICENSE
    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 
@@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
     License.  (Exception: if the Program itself is interactive but
     does not normally print such an announcement, your work based on
     the Program is not required to print an announcement.)
-\f
+
 These requirements apply to the modified work as a whole.  If
 identifiable sections of that work are not derived from the Program,
 and can be reasonably considered independent and separate works in
@@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
 access to copy the source code from the same place counts as
 distribution of the source code, even though third parties are not
 compelled to copy the source along with the object code.
-\f
+
   4. You may not copy, modify, sublicense, or distribute the Program
 except as expressly provided under this License.  Any attempt
 otherwise to copy, modify, sublicense or distribute the Program is
@@ -225,7 +225,7 @@ impose that choice.
 
 This section is intended to make thoroughly clear what is believed to
 be a consequence of the rest of this License.
-\f
+
   8. If the distribution and/or use of the Program is restricted in
 certain countries either by patents or by copyrighted interfaces, the
 original copyright holder who places the Program under this License
@@ -278,7 +278,7 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGES.
 
                     END OF TERMS AND CONDITIONS
-\f
+
            How to Apply These Terms to Your New Programs
 
   If you develop a new program, and you want it to be of the greatest
@@ -303,17 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
     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
-
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
 Also add information on how to contact you by electronic and paper mail.
 
 If the program is interactive, make it output a short notice like this
 when it starts in an interactive mode:
 
-    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision version 69, Copyright (C) year name of author
     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
     This is free software, and you are welcome to redistribute it
     under certain conditions; type `show c' for details.
@@ -336,5 +335,5 @@ necessary.  Here is a sample; alter the names:
 This General Public License does not permit incorporating your program into
 proprietary programs.  If your program is a subroutine library, you may
 consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
+library.  If this is what you want to do, use the GNU Lesser General
 Public License instead of this License.
diff --git a/INSTALL b/INSTALL
index d3c5b40a94091285c27361905f591af64c1f7b21..200806c586303f2258464fa4c13299aa420af941 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -234,4 +234,3 @@ an Autoconf bug.  Until the bug is fixed you can use this workaround:
 
 `configure' also accepts some other, not widely useful, options.  Run
 `configure --help' for more details.
-
index 86f2fad550b556dfc24db150bc8bb8b9ac0e9776..b0d059ea0968b8e49be6217cfc3c8382116abf15 100644 (file)
@@ -1 +1 @@
-SUBDIRS=lib ccload s51 ccmanual ccdump aoload
+SUBDIRS=src aoview lib ccload s51 ccmanual ccdump aoload
diff --git a/README b/README
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1244f8492d5db6566fc79cd8a02fe5bb8b0bd61f 100644 (file)
--- a/README
+++ b/README
@@ -0,0 +1,54 @@
+       AltOS - 8051 operating system for Altus-Metrum projects
+
+Copyright and License
+
+       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.
+
+Parameters:
+
+ * Multi-tasking
+ * Non-preemptive
+ * Unix-style sleep/wakeup scheduling
+ * Strict round-robin, no priorities
+
+API:
+
+       void ao_sleep(void *wchan)
+
+               Puts current task to sleep. Will wake up when wchan is signalled
+       
+       void ao_wakeup(void *wchan)
+
+               Wakeup all tasks sleeping on wchan
+
+       void ao_add_task(struct ao_task *task, void (*start)(void))
+
+               Adds a task to the queue of available tasks
+
+       void ao_start_scheduler(void)
+
+               Invokes the scheduler, starting the operating system
+
+       void ao_yield(void)
+
+               Switches to another task which is ready to run. Allows
+               tasks which want to run for a while to give up the CPU
+               without needing to sleep
+
+       void ao_panic(uint8_t reason)
+
+               Any fatal error should call this function, which can
+               display the error code in some cryptic fashion.
index a36ad375e6c8a8fd006b25ecd78f1352a3f5c666..b84a88a68f25c9b07530d6bb5e7d5b99385174ef 100644 (file)
@@ -128,7 +128,7 @@ main (int argc, char **argv)
        serial_string = argv[2];
        if (serial_string == NULL)
                usage(argv[0]);
-       
+
        file = fopen(filename, "r");
        if (!file) {
                perror(filename);
@@ -170,7 +170,7 @@ main (int argc, char **argv)
                        AO_SERIAL_NUMBER);
                exit(1);
        }
-       
+
        usb_descriptors = AO_USB_DESCRIPTORS - image->address;
        string_num = 0;
        while (image->data[usb_descriptors] != 0 && usb_descriptors < image->length) {
@@ -185,7 +185,7 @@ main (int argc, char **argv)
                fprintf(stderr, "Cannot rewrite serial string at %04x\n", AO_USB_DESCRIPTORS);
                exit(1);
        }
-               
+
        serial_ucs2_len = image->data[usb_descriptors] - 2;
        serial_ucs2 = malloc(serial_ucs2_len);
        if (!serial_ucs2) {
@@ -200,11 +200,11 @@ main (int argc, char **argv)
        }
        if (!rewrite(image, usb_descriptors + 2 + image->address, serial_ucs2, serial_ucs2_len))
                usage(argv[0]);
-       
+
        dbg = ccdbg_open();
        if (!dbg)
                exit (1);
-       
+
        ccdbg_add_debug(CC_DEBUG_FLASH);
 
        ccdbg_debug_mode(dbg);
diff --git a/aoview/.gitignore b/aoview/.gitignore
new file mode 100644 (file)
index 0000000..33f40fc
--- /dev/null
@@ -0,0 +1,3 @@
+*.o
+aoview
+aoview_glade.h
diff --git a/aoview/Makefile.am b/aoview/Makefile.am
new file mode 100644 (file)
index 0000000..be3fbac
--- /dev/null
@@ -0,0 +1,28 @@
+VERSION=$(shell git describe)
+AM_CFLAGS=$(GNOME_CFLAGS) -I$(top_srcdir)/src -DAOVIEW_VERSION=\"$(VERSION)\"
+
+bin_PROGRAMS=aoview
+
+aoview_LDADD=$(GNOME_LIBS)
+
+aoview_SOURCES = \
+       aoview_main.c \
+       aoview_dev.c \
+       aoview_dev_dialog.c \
+       aoview_serial.c \
+       aoview_monitor.c \
+       aoview_state.c \
+       aoview_convert.c \
+       aoview_log.c \
+       aoview_table.c \
+       aoview_util.c \
+       aoview_file.c \
+       aoview_eeprom.c \
+       aoview.h
+
+BUILT_SOURCES = aoview_glade.h
+
+CLEANFILES = aoview_glade.h
+
+aoview_glade.h: aoview.glade
+       sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/"/' $< > $@
diff --git a/aoview/aoview.glade b/aoview/aoview.glade
new file mode 100644 (file)
index 0000000..f398999
--- /dev/null
@@ -0,0 +1,522 @@
+<?xml version="1.0"?>
+<glade-interface>
+  <!-- interface-requires gtk+ 2.16 -->
+  <!-- interface-naming-policy project-wide -->
+  <widget class="GtkWindow" id="aoview">
+    <property name="width_request">300</property>
+    <property name="height_request">540</property>
+    <property name="visible">True</property>
+    <property name="title" translatable="yes">AltOS View</property>
+    <child>
+      <widget class="GtkVBox" id="vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <widget class="GtkMenuBar" id="menubar1">
+            <property name="visible">True</property>
+            <child>
+              <widget class="GtkMenuItem" id="menuitem1">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_File</property>
+                <property name="use_underline">True</property>
+                <child>
+                  <widget class="GtkMenu" id="menu1">
+                    <property name="visible">True</property>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="imagemenuitem1">
+                        <property name="label">gtk-new</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="imagemenuitem2">
+                        <property name="label">gtk-open</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="imagemenuitem3">
+                        <property name="label">gtk-save</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="imagemenuitem4">
+                        <property name="label">gtk-save-as</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
+                        <property name="visible">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="imagemenuitem5">
+                        <property name="label">gtk-quit</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                        <signal name="activate" handler="gtk_main_quit"/>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkMenuItem" id="menuitem2">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_Edit</property>
+                <property name="use_underline">True</property>
+                <child>
+                  <widget class="GtkMenu" id="menu2">
+                    <property name="visible">True</property>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="imagemenuitem6">
+                        <property name="label">gtk-cut</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="imagemenuitem7">
+                        <property name="label">gtk-copy</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="imagemenuitem8">
+                        <property name="label">gtk-paste</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="imagemenuitem9">
+                        <property name="label">gtk-delete</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkMenuItem" id="menuitem3">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_Device</property>
+                <property name="use_underline">True</property>
+                <child>
+                  <widget class="GtkMenu" id="menu4">
+                    <property name="visible">True</property>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="ao_connect">
+                        <property name="label" translatable="yes">_Connect to device</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">False</property>
+                        <signal name="activate_item" handler="gtk_widget_show" object="device_connect_dialog" after="yes"/>
+                        <signal name="activate" handler="gtk_widget_show" object="device_connect_dialog" after="yes"/>
+                        <child internal-child="image">
+                          <widget class="GtkImage" id="image1">
+                            <property name="visible">True</property>
+                            <property name="stock">gtk-connect</property>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="ao_disconnect">
+                        <property name="label" translatable="yes">_Disconnect</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">False</property>
+                        <child internal-child="image">
+                          <widget class="GtkImage" id="image2">
+                            <property name="visible">True</property>
+                            <property name="stock">gtk-disconnect</property>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkSeparatorMenuItem" id="seperator">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="ao_savelog">
+                        <property name="label" translatable="yes">_Save EEPROM data</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">False</property>
+                        <signal name="activate_item" handler="gtk_widget_show" object="device_connect_dialog" after="yes"/>
+                        <signal name="activate" handler="gtk_widget_show" object="device_connect_dialog"/>
+                        <child internal-child="image">
+                          <widget class="GtkImage" id="image5">
+                            <property name="visible">True</property>
+                            <property name="stock">gtk-save</property>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkMenuItem" id="menuitem5">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_Log</property>
+                <property name="use_underline">True</property>
+                <child>
+                  <widget class="GtkMenu" id="menu5">
+                    <property name="visible">True</property>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="log_new">
+                        <property name="label" translatable="yes">_New log</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">False</property>
+                        <child internal-child="image">
+                          <widget class="GtkImage" id="image3">
+                            <property name="visible">True</property>
+                            <property name="stock">gtk-new</property>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="file_configure">
+                        <property name="label" translatable="yes">_Configure Log</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">False</property>
+                        <signal name="activate" handler="gtk_widget_show" object="file_chooser_dialog" after="yes"/>
+                        <child internal-child="image">
+                          <widget class="GtkImage" id="image4">
+                            <property name="visible">True</property>
+                            <property name="stock">gtk-preferences</property>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkMenuItem" id="menuitem4">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_Help</property>
+                <property name="use_underline">True</property>
+                <child>
+                  <widget class="GtkMenu" id="menu3">
+                    <property name="visible">True</property>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="imagemenuitem10">
+                        <property name="label">gtk-about</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                        <signal name="activate" handler="gtk_widget_show" object="about_dialog" after="yes"/>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkTreeView" id="dataview">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="headers_clickable">False</property>
+            <property name="show_expanders">False</property>
+            <property name="enable_grid_lines">both</property>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkDialog" id="device_connect_dialog">
+    <property name="border_width">5</property>
+    <property name="type_hint">normal</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkTreeView" id="dev_list">
+            <property name="width_request">300</property>
+            <property name="height_request">100</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="headers_clickable">False</property>
+            <property name="rules_hint">True</property>
+            <property name="search_column">0</property>
+            <property name="show_expanders">False</property>
+            <property name="level_indentation">1</property>
+            <property name="enable_grid_lines">both</property>
+            <property name="enable_tree_lines">True</property>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <widget class="GtkButton" id="cancel_button">
+                <property name="label" translatable="yes">gtk-cancel</property>
+                <property name="response_id">1</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_underline">True</property>
+                <property name="use_stock">True</property>
+                <signal name="clicked" handler="gtk_widget_hide" object="device_connect_dialog" after="yes"/>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkButton" id="connect_button">
+                <property name="label" translatable="yes">gtk-connect</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="has_default">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkFileChooserDialog" id="file_chooser_dialog">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Configure Log Directory</property>
+    <property name="type_hint">dialog</property>
+    <property name="has_separator">False</property>
+    <property name="action">select-folder</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox2">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area2">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <widget class="GtkButton" id="file_configure_cancel">
+                <property name="label" translatable="yes">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+                <signal name="clicked" handler="gtk_widget_hide" object="file_chooser_dialog"/>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkButton" id="file_configure_ok">
+                <property name="label" translatable="yes">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="has_default">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkMessageDialog" id="file_fail_dialog">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Failed to create log</property>
+    <property name="type_hint">normal</property>
+    <property name="skip_taskbar_hint">True</property>
+    <property name="transient_for">aoview</property>
+    <property name="message_type">error</property>
+    <property name="buttons">close</property>
+    <property name="text">Cannot create log file</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox4">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area4">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkMessageDialog" id="dev_open_fail_dialog">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Failed to open device</property>
+    <property name="type_hint">normal</property>
+    <property name="skip_taskbar_hint">True</property>
+    <property name="transient_for">aoview</property>
+    <property name="message_type">error</property>
+    <property name="buttons">close</property>
+    <property name="text">Cannot open device</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox6">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area6">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkAboutDialog" id="about_dialog">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">About AoView</property>
+    <property name="resizable">False</property>
+    <property name="type_hint">normal</property>
+    <property name="transient_for">aoview</property>
+    <property name="has_separator">False</property>
+    <property name="program_name">AoView</property>
+    <property name="copyright" translatable="yes">Copyright &#xA9; 2009 Keith Packard</property>
+    <property name="comments" translatable="yes">AltOS data capture and display.</property>
+    <property name="website">http://altusmetrum.org</property>
+    <property name="license" translatable="yes">AoView 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.
+
+AoView 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 AoView; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</property>
+    <property name="authors">Keith Packard &lt;keithp@keithp.com&gt;</property>
+    <property name="wrap_license">True</property>
+    <signal name="close" handler="gtk_widget_hide" object="about_dialog" after="yes"/>
+    <signal name="response" handler="gtk_widget_hide" object="about_dialog" after="yes"/>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox7">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area7">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkMessageDialog" id="ao_save_done">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">EEPROM save complete</property>
+    <property name="type_hint">normal</property>
+    <property name="skip_taskbar_hint">True</property>
+    <property name="transient_for">aoview</property>
+    <property name="has_separator">False</property>
+    <property name="buttons">close</property>
+    <property name="text">Saving EEPROM data as</property>
+    <property name="secondary_text">&lt;filename&gt;</property>
+    <signal name="close" handler="gtk_widget_hide" object="ao_save_done"/>
+    <signal name="response" handler="gtk_widget_hide" object="ao_save_done"/>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox11">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area11">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>
diff --git a/aoview/aoview.h b/aoview/aoview.h
new file mode 100644 (file)
index 0000000..4eb4cd8
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * 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 _AOVIEW_H_
+#define _AOVIEW_H_
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <err.h>
+#include <errno.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <assert.h>
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <gconf/gconf-client.h>
+
+struct usbdev {
+       char    *sys;
+       char    *tty;
+       char    *manufacturer;
+       char    *product;
+       char    *serial;
+       int     idProduct;
+       int     idVendor;
+};
+
+struct aostate {
+       char    callsign[16];
+       int     serial;
+       int     rssi;
+       char    state[16];
+       int     tick;
+       int     accel;
+       int     pres;
+       int     temp;
+       int     batt;
+       int     drogue;
+       int     main;
+       int     flight_accel;
+       int     ground_accel;
+       int     flight_vel;
+       int     flight_pres;
+       int     ground_pres;
+       int     nsat;
+       int     locked;
+       struct {
+               int hour;
+               int minute;
+               int second;
+       } gps_time;
+       double  lat;
+       double  lon;
+       int     alt;
+};
+
+void
+aoview_monitor_disconnect(void);
+
+gboolean
+aoview_monitor_connect(char *tty);
+
+struct aoview_serial *
+aoview_serial_open(const char *tty);
+
+void
+aoview_serial_close(struct aoview_serial *serial);
+
+typedef void (*aoview_serial_callback)(gpointer user_data, struct aoview_serial *serial, gint revents);
+
+void
+aoview_serial_set_callback(struct aoview_serial *serial,
+                          aoview_serial_callback func,
+                          gpointer data,
+                          GDestroyNotify notify);
+
+void
+aoview_serial_printf(struct aoview_serial *serial, char *format, ...);
+
+int
+aoview_serial_read(struct aoview_serial *serial, char *buf, int len);
+
+int
+aoview_serial_getc(struct aoview_serial *serial);
+
+void
+aoview_dev_dialog_init(GladeXML *xml);
+
+int
+aoview_usb_scan(struct usbdev ***devs_ret);
+
+void
+aoview_usbdev_free(struct usbdev *usbdev);
+
+void
+aoview_state_notify(struct aostate *state);
+
+void
+aoview_state_new(void);
+
+void
+aoview_state_init(GladeXML *xml);
+
+int16_t
+aoview_pres_to_altitude(int16_t pres);
+
+int16_t
+aoview_altitude_to_pres(int16_t alt);
+
+char *
+aoview_fullname (char *dir, char *file);
+
+char *
+aoview_basename(char *file);
+
+GtkTreeViewColumn *
+aoview_add_plain_text_column (GtkTreeView *view, const gchar *title, gint model_column, gint width);
+
+int
+aoview_mkdir(char *dir);
+
+void
+aoview_log_init(GladeXML *xml);
+
+void
+aoview_log_set_serial(int serial);
+
+int
+aoview_log_get_serial(void);
+
+void
+aoview_log_printf(char *format, ...);
+
+void
+aoview_log_new(void);
+
+void
+aoview_table_start(void);
+
+void
+aoview_table_add_row(char *label, char *format, ...);
+
+void
+aoview_table_finish(void);
+
+void
+aoview_table_init(GladeXML *xml);
+
+void
+aoview_table_clear(void);
+
+struct aoview_file;
+
+void
+aoview_file_finish(struct aoview_file *file);
+
+gboolean
+aoview_file_start(struct aoview_file *file);
+
+const char *
+aoview_file_name(struct aoview_file *file);
+
+void
+aoview_file_set_serial(struct aoview_file *file, int serial);
+
+int
+aoview_file_get_serial(struct aoview_file *file);
+
+void
+aoview_file_printf(struct aoview_file *file, char *format, ...);
+
+void
+aoview_file_vprintf(struct aoview_file *file, char *format, va_list ap);
+
+struct aoview_file *
+aoview_file_new(char *ext);
+
+void
+aoview_file_destroy(struct aoview_file *file);
+
+void
+aoview_file_init(GladeXML *xml);
+
+/* aoview_eeprom.c */
+
+gboolean
+aoview_eeprom_save(const char *device);
+
+void
+aoview_eeprom_init(GladeXML *xml);
+
+#endif /* _AOVIEW_H_ */
diff --git a/aoview/aoview_convert.c b/aoview/aoview_convert.c
new file mode 100644 (file)
index 0000000..0241664
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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 "aoview.h"
+
+static int16_t altitude_table[2048] = {
+#include "altitude.h"
+};
+
+int16_t
+aoview_pres_to_altitude(int16_t pres)
+{
+       pres = pres >> 4;
+       if (pres < 0) pres = 0;
+       if (pres > 2047) pres = 2047;
+       return altitude_table[pres];
+}
+
+int16_t
+aoview_altitude_to_pres(int16_t alt)
+{
+       int16_t pres;
+
+       for (pres = 0; pres < 2047; pres++)
+               if (altitude_table[pres] <= alt)
+                       break;
+       return pres << 4;
+}
diff --git a/aoview/aoview_dev.c b/aoview/aoview_dev.c
new file mode 100644 (file)
index 0000000..2fabfe2
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * 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 "aoview.h"
+#include <ctype.h>
+#include <dirent.h>
+
+static char *
+load_string(char *dir, char *file)
+{
+       char    *full = aoview_fullname(dir, file);
+       char    line[4096];
+       char    *r;
+       FILE    *f;
+       int     rlen;
+
+       f = fopen(full, "r");
+       free(full);
+       if (!f)
+               return NULL;
+       r = fgets(line, sizeof (line), f);
+       fclose(f);
+       if (!r)
+               return NULL;
+       rlen = strlen(r);
+       if (r[rlen-1] == '\n')
+               r[rlen-1] = '\0';
+       return strdup(r);
+}
+
+static int
+load_hex(char *dir, char *file)
+{
+       char    *line;
+       char    *end;
+       long    i;
+
+       line = load_string(dir, file);
+       if (!line)
+               return -1;
+       i = strtol(line, &end, 16);
+       free(line);
+       if (end == line)
+               return -1;
+       return i;
+}
+
+static int
+dir_filter_tty(const struct dirent *d)
+{
+       return strncmp(d->d_name, "tty:", 4) == 0;
+}
+
+static char *
+usb_tty(char *sys)
+{
+       char *base;
+       int num_configs;
+       int config;
+       struct dirent **namelist;
+       int interface;
+       int num_interfaces;
+       char endpoint_base[20];
+       char *endpoint_full;
+       int ntty;
+       char *tty;
+
+       base = aoview_basename(sys);
+       num_configs = load_hex(sys, "bNumConfigurations");
+       num_interfaces = load_hex(sys, "bNumInterfaces");
+       for (config = 1; config <= num_configs; config++) {
+               for (interface = 0; interface < num_interfaces; interface++) {
+                       sprintf(endpoint_base, "%s:%d.%d",
+                               base, config, interface);
+                       endpoint_full = aoview_fullname(sys, endpoint_base);
+                       ntty = scandir(endpoint_full, &namelist,
+                                      dir_filter_tty,
+                                      alphasort);
+                       free(endpoint_full);
+                       if (ntty > 0) {
+                               tty = aoview_fullname("/dev", namelist[0]->d_name + 4);
+                               free(namelist);
+                               return tty;
+                       }
+               }
+       }
+       return NULL;
+}
+
+static struct usbdev *
+usb_scan_device(char *sys)
+{
+       struct usbdev *usbdev;
+
+       usbdev = calloc(1, sizeof (struct usbdev));
+       if (!usbdev)
+               return NULL;
+       usbdev->sys = strdup(sys);
+       usbdev->manufacturer = load_string(sys, "manufacturer");
+       usbdev->product = load_string(sys, "product");
+       usbdev->serial = load_string(sys, "serial");
+       usbdev->idProduct = load_hex(sys, "idProduct");
+       usbdev->idVendor = load_hex(sys, "idVendor");
+       usbdev->tty = usb_tty(sys);
+       return usbdev;
+}
+
+void
+aoview_usbdev_free(struct usbdev *usbdev)
+{
+       free(usbdev->sys);
+       free(usbdev->manufacturer);
+       free(usbdev->product);
+       free(usbdev->serial);
+       free(usbdev->tty);
+       free(usbdev);
+}
+
+#define USB_DEVICES    "/sys/bus/usb/devices"
+
+static int
+dir_filter_dev(const struct dirent *d)
+{
+       const char      *n = d->d_name;
+       char    c;
+
+       while ((c = *n++)) {
+               if (isdigit(c))
+                       continue;
+               if (c == '-')
+                       continue;
+               if (c == '.' && n != d->d_name + 1)
+                       continue;
+               return 0;
+       }
+       return 1;
+}
+
+int
+aoview_usb_scan(struct usbdev ***devs_ret)
+{
+       int             n;
+       int             ndev = 0;
+       int             e;
+       struct dirent   **ents;
+       char            *dir;
+       struct usbdev   **devs = NULL;
+       struct usbdev   *dev;
+
+       n = scandir (USB_DEVICES, &ents,
+                    dir_filter_dev,
+                    alphasort);
+       if (!n)
+               return 0;
+       for (e = 0; e < n; e++) {
+               dir = aoview_fullname(USB_DEVICES, ents[e]->d_name);
+               dev = usb_scan_device(dir);
+               free(dir);
+               if (dev->idVendor == 0xfffe && dev->tty) {
+                       if (devs)
+                               devs = realloc(devs, ndev + 1 * sizeof (struct usbdev *));
+                       else
+                               devs = malloc (sizeof (struct usbdev *));
+                       devs[ndev++] = dev;
+               }
+       }
+       free(ents);
+       *devs_ret = devs;
+       return ndev;
+}
diff --git a/aoview/aoview_dev_dialog.c b/aoview/aoview_dev_dialog.c
new file mode 100644 (file)
index 0000000..3f92085
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * 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 "aoview.h"
+
+static void
+aoview_dev_dialog_map(GtkWidget *widget, gpointer data)
+{
+       GtkTreeView     *dev_list = data;
+       GtkListStore    *list_store;
+       GtkTreeIter     iter;
+       int             ndev, n;
+       struct usbdev   **devs;
+
+       list_store = gtk_list_store_new(3,
+                                       G_TYPE_STRING,
+                                       G_TYPE_STRING,
+                                       G_TYPE_STRING);
+
+       ndev = aoview_usb_scan(&devs);
+       for (n = 0; n < ndev; n++) {
+               gtk_list_store_append(list_store, &iter);
+               gtk_list_store_set(list_store, &iter,
+                                  0, devs[n]->product,
+                                  1, devs[n]->serial,
+                                  2, devs[n]->tty,
+                                  -1);
+       }
+       gtk_tree_view_set_model (dev_list, GTK_TREE_MODEL(list_store));
+       g_object_unref(G_OBJECT(list_store));
+       gtk_tree_view_columns_autosize(dev_list);
+}
+
+static GtkMessageDialog *dev_open_fail_dialog;
+
+static void
+aoview_dev_open_failed(char *name)
+{
+       char    *utf8_file;
+       utf8_file = g_filename_to_utf8(name, -1, NULL, NULL, NULL);
+       if (!utf8_file)
+               utf8_file = name;
+       gtk_message_dialog_format_secondary_text(dev_open_fail_dialog,
+                                                "\"%s\"", utf8_file);
+       if (utf8_file != name)
+               g_free(utf8_file);
+       gtk_dialog_run(GTK_DIALOG(dev_open_fail_dialog));
+       gtk_widget_hide(GTK_WIDGET(dev_open_fail_dialog));
+}
+
+gboolean       dialog_save_log;
+
+static void
+aoview_dev_selected(GtkTreeModel *model,
+                   GtkTreePath *path,
+                   GtkTreeIter *iter,
+                   gpointer data)
+{
+       gchar *string;
+       gtk_tree_model_get(model, iter,
+                          2, &string,
+                          -1);
+       if (dialog_save_log) {
+               dialog_save_log = FALSE;
+               if (!aoview_eeprom_save(string))
+                       aoview_dev_open_failed(string);
+       } else {
+               if (!aoview_monitor_connect(string))
+                       aoview_dev_open_failed(string);
+       }
+}
+
+static GtkWidget       *dialog;
+
+static void
+aoview_dev_dialog_connect(GtkWidget *widget, gpointer data)
+{
+       GtkTreeView             *dev_list = data;
+       GtkListStore            *list_store;
+       GtkTreeSelection        *tree_selection;
+
+       list_store = GTK_LIST_STORE(gtk_tree_view_get_model(dev_list));
+       tree_selection = gtk_tree_view_get_selection(dev_list);
+       gtk_tree_selection_selected_foreach(tree_selection,
+                                           aoview_dev_selected,
+                                           data);
+       gtk_widget_hide(dialog);
+}
+
+static void
+aoview_dev_disconnect(GtkWidget *widget)
+{
+       aoview_monitor_disconnect();
+}
+
+static void
+aoview_dev_savelog(GtkWidget *widget, gpointer data)
+{
+       dialog_save_log = TRUE;
+       gtk_widget_show(dialog);
+}
+
+#define _(a) a
+
+void
+aoview_dev_dialog_init(GladeXML *xml)
+{
+       GtkTreeView     *dev_list;
+       GtkWidget       *connect_button;
+       GtkTreeSelection        *dev_selection;
+       GtkWidget       *ao_disconnect;
+       GtkWidget       *ao_savelog;
+
+       dialog = glade_xml_get_widget(xml, "device_connect_dialog");
+       assert(dialog);
+
+       dev_list = GTK_TREE_VIEW(glade_xml_get_widget(xml, "dev_list"));
+       assert(dev_list);
+
+       aoview_add_plain_text_column(dev_list, _("Product"), 0, 16);
+       aoview_add_plain_text_column(dev_list, _("Serial"),  1, 8);
+       aoview_add_plain_text_column(dev_list, _("Device"), 2, 13);
+
+       dev_selection = gtk_tree_view_get_selection(dev_list);
+       gtk_tree_selection_set_mode(dev_selection, GTK_SELECTION_SINGLE);
+
+       g_signal_connect(G_OBJECT(dialog), "map",
+                        G_CALLBACK(aoview_dev_dialog_map),
+                        dev_list);
+
+       connect_button = glade_xml_get_widget(xml, "connect_button");
+       assert(connect_button);
+
+       g_signal_connect(G_OBJECT(connect_button), "clicked",
+                        G_CALLBACK(aoview_dev_dialog_connect),
+                        dev_list);
+
+
+       ao_disconnect = glade_xml_get_widget(xml, "ao_disconnect");
+       assert(ao_disconnect);
+
+       g_signal_connect(G_OBJECT(ao_disconnect), "activate",
+                        G_CALLBACK(aoview_dev_disconnect),
+                        ao_disconnect);
+
+       ao_savelog = glade_xml_get_widget(xml, "ao_savelog");
+       assert(ao_savelog);
+
+       g_signal_connect(G_OBJECT(ao_savelog), "activate",
+                        G_CALLBACK(aoview_dev_savelog),
+                        dialog);
+       dev_open_fail_dialog = GTK_MESSAGE_DIALOG(glade_xml_get_widget(xml, "dev_open_fail_dialog"));
+       assert(dev_open_fail_dialog);
+}
diff --git a/aoview/aoview_eeprom.c b/aoview/aoview_eeprom.c
new file mode 100644 (file)
index 0000000..826afc4
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * 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 "aoview.h"
+
+#define EEPROM_LEN     1024
+
+static struct aoview_file      *eeprom_file;
+static char                    eeprom_line[EEPROM_LEN + 1];
+static int                     eeprom_pos;
+static GtkMessageDialog                *eeprom_save_done;
+static GtkWidget               *eeprom_save_close;
+static gboolean                        eeprom_save_shown;
+
+static void
+aoview_eeprom_disconnect(struct aoview_serial *serial)
+{
+       aoview_file_finish(eeprom_file);
+}
+
+static void
+aoview_eeprom_done(struct aoview_serial *serial)
+{
+       gtk_window_set_title(GTK_WINDOW(eeprom_save_done),
+                            "EEPROM data saved");
+       gtk_message_dialog_set_markup(eeprom_save_done,
+                                     "<b>EEPROM data saved as</b>");
+       if (!eeprom_save_shown)
+               gtk_widget_show(GTK_WIDGET(eeprom_save_done));
+       eeprom_save_close = gtk_window_get_default_widget(GTK_WINDOW(eeprom_save_done));
+       if (eeprom_save_close)
+               gtk_widget_set_sensitive(eeprom_save_close, TRUE);
+       aoview_eeprom_disconnect(serial);
+}
+
+static gboolean
+aoview_eeprom_parse(struct aoview_serial *serial,
+                   char *line)
+{
+       char            cmd;
+       int             tick;
+       int             a;
+       int             b;
+       int             serial_number;
+       const char      *name;
+       char            *utf8_name;
+
+       if (!strcmp(line, "end")) {
+               aoview_eeprom_done(serial);
+               return FALSE;
+       }
+       if (sscanf(line, "serial-number %u", &serial_number) == 1) {
+               aoview_file_set_serial(eeprom_file, serial_number);
+       } else if (sscanf(line, "%c %x %x %x", &cmd, &tick, &a, &b) == 4) {
+               aoview_file_printf(eeprom_file, "%s\n", line);
+               if (cmd == 'S' && a == 8) {
+                       aoview_eeprom_done(serial);
+                       return FALSE;
+               }
+
+               if (!eeprom_save_shown)
+               {
+                       name = aoview_file_name(eeprom_file);
+                       if (name) {
+                               utf8_name = g_filename_to_utf8(name, -1, NULL, NULL, NULL);
+                               if (!utf8_name)
+                                       utf8_name = (char *) name;
+                               gtk_widget_set_sensitive(eeprom_save_close, FALSE);
+                               gtk_window_set_title(GTK_WINDOW(eeprom_save_done),
+                                                    "Saving EEPROM data");
+                               gtk_message_dialog_set_markup(eeprom_save_done,
+                                                             "<b>Saving EEPROM data as</b>");
+                               gtk_message_dialog_format_secondary_text(eeprom_save_done, "%s",
+                                                                        utf8_name);
+                               if (utf8_name != name)
+                                       g_free(utf8_name);
+                               gtk_container_check_resize(GTK_CONTAINER(eeprom_save_done));
+                               gtk_widget_show(GTK_WIDGET(eeprom_save_done));
+                               eeprom_save_shown = TRUE;
+                               eeprom_save_close = gtk_window_get_default_widget(GTK_WINDOW(eeprom_save_done));
+                               if (eeprom_save_close)
+                                       gtk_widget_set_sensitive(eeprom_save_close, FALSE);
+                       }
+               }
+       }
+       return TRUE;
+}
+
+static void
+aoview_eeprom_callback(gpointer user_data,
+                      struct aoview_serial *serial,
+                      gint revents)
+{
+       int     c;
+
+       if (revents & (G_IO_HUP|G_IO_ERR)) {
+               aoview_eeprom_disconnect(serial);
+               return;
+       }
+       if (revents & G_IO_IN) {
+               for (;;) {
+                       c = aoview_serial_getc(serial);
+                       if (c == -1)
+                               break;
+                       if (c == '\r')
+                               continue;
+                       if (c == '\n') {
+                               eeprom_line[eeprom_pos] = '\0';
+                               if (eeprom_pos)
+                               if (!aoview_eeprom_parse(serial, eeprom_line))
+                                       break;
+                               eeprom_pos = 0;
+                       } else if (eeprom_pos < EEPROM_LEN)
+                               eeprom_line[eeprom_pos++] = c;
+               }
+       }
+}
+
+gboolean
+aoview_eeprom_save(const char *device)
+{
+       struct aoview_serial    *serial;
+
+       gtk_widget_hide(GTK_WIDGET(eeprom_save_done));
+       eeprom_save_shown = FALSE;
+       serial = aoview_serial_open(device);
+       if (!serial)
+               return FALSE;
+       aoview_serial_set_callback(serial, aoview_eeprom_callback, serial, NULL);
+       aoview_serial_printf(serial, "v\nl\n");
+       return TRUE;
+}
+
+void
+aoview_eeprom_init(GladeXML *xml)
+{
+       eeprom_file = aoview_file_new("eeprom");
+       assert(eeprom_file);
+
+       eeprom_save_done = GTK_MESSAGE_DIALOG(glade_xml_get_widget(xml, "ao_save_done"));
+       assert(eeprom_save_done);
+
+}
diff --git a/aoview/aoview_file.c b/aoview/aoview_file.c
new file mode 100644 (file)
index 0000000..4a8841d
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * 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 "aoview.h"
+
+static char *aoview_file_dir;
+
+#define ALTOS_DIR_PATH "/apps/aoview/log_dir"
+#define DEFAULT_DIR    "AltOS"
+
+struct aoview_file {
+       char    *ext;
+       FILE    *file;
+       char    *name;
+       int     failed;
+       int     serial;
+       int     sequence;
+};
+
+static void
+aoview_file_save_conf(void)
+{
+       GConfClient     *gconf_client;
+
+       gconf_client = gconf_client_get_default();
+       if (gconf_client)
+       {
+               gconf_client_set_string(gconf_client,
+                                       ALTOS_DIR_PATH,
+                                       aoview_file_dir,
+                                       NULL);
+               g_object_unref(G_OBJECT(gconf_client));
+       }
+}
+
+static void
+aoview_file_configure(GtkWidget *widget, gpointer data)
+{
+       GtkFileChooser *chooser = data;
+       aoview_file_dir = gtk_file_chooser_get_filename(chooser);
+       aoview_file_save_conf();
+       gtk_widget_hide(GTK_WIDGET(chooser));
+}
+
+void
+aoview_file_finish(struct aoview_file *file)
+{
+       if (file->file) {
+               fclose(file->file);
+               file->file = NULL;
+               free(file->name);
+               file->name = NULL;
+       }
+       file->failed = 0;
+}
+
+const char *
+aoview_file_name(struct aoview_file *file)
+{
+       return file->name;
+}
+
+static GtkMessageDialog *file_fail_dialog;
+
+static void
+aoview_file_open_failed(char *name)
+{
+       char    *utf8_file;
+       utf8_file = g_filename_to_utf8(name, -1, NULL, NULL, NULL);
+       if (!utf8_file)
+               utf8_file = name;
+       gtk_message_dialog_format_secondary_text(file_fail_dialog,
+                                                "\"%s\"", utf8_file);
+       if (utf8_file != name)
+               g_free(utf8_file);
+       gtk_widget_show(GTK_WIDGET(file_fail_dialog));
+}
+
+gboolean
+aoview_file_start(struct aoview_file *file)
+{
+       char            base[50];
+       struct tm       tm;
+       time_t          now;
+       char            *full;
+       int             r;
+
+       if (file->file)
+               return TRUE;
+
+       if (file->failed)
+               return FALSE;
+
+       now = time(NULL);
+       (void) localtime_r(&now, &tm);
+       aoview_mkdir(aoview_file_dir);
+       for (;;) {
+               snprintf(base, sizeof (base), "%04d-%02d-%02d-serial-%03d-flight-%03d.%s",
+                       tm.tm_year + 1900,
+                       tm.tm_mon + 1,
+                       tm.tm_mday,
+                       file->serial,
+                       file->sequence,
+                       file->ext);
+               full = aoview_fullname(aoview_file_dir, base);
+               r = access(full, F_OK);
+               if (r < 0) {
+                       file->file = fopen(full, "w");
+                       if (!file->file) {
+                               aoview_file_open_failed(full);
+                               free(full);
+                               file->failed = 1;
+                               return FALSE;
+                       } else {
+                               setlinebuf(file->file);
+                               file->name = full;
+                               return TRUE;
+                       }
+               }
+               free(full);
+               file->sequence++;
+       }
+}
+
+void
+aoview_file_vprintf(struct aoview_file *file, char *format, va_list ap)
+{
+       if (!aoview_file_start(file))
+               return;
+       vfprintf(file->file, format, ap);
+}
+
+void
+aoview_file_printf(struct aoview_file *file, char *format, ...)
+{
+       va_list ap;
+
+       va_start(ap, format);
+       aoview_file_vprintf(file, format, ap);
+       va_end(ap);
+}
+
+struct aoview_file *
+aoview_file_new(char *ext)
+{
+       struct aoview_file      *file;
+
+       file = calloc (1, sizeof (struct aoview_file));
+       if (!file)
+               return NULL;
+       file->ext = strdup(ext);
+       if (!file->ext) {
+               free(file);
+               return NULL;
+       }
+       return file;
+}
+
+void
+aoview_file_destroy(struct aoview_file *file)
+{
+       if (file->file)
+               fclose(file->file);
+       if (file->name)
+               free(file->name);
+       free(file->ext);
+       free(file);
+}
+
+void
+aoview_file_set_serial(struct aoview_file *file, int serial)
+{
+       if (serial != file->serial)
+               aoview_file_finish(file);
+       file->serial = serial;
+}
+
+int
+aoview_file_get_serial(struct aoview_file *file)
+{
+       return file->serial;
+}
+
+void
+aoview_file_init(GladeXML *xml)
+{
+       GConfClient     *gconf_client;
+       char            *file_dir = NULL;
+       GtkFileChooser  *file_chooser_dialog;
+       GtkWidget       *file_configure_ok;
+
+       g_type_init();
+       gconf_client = gconf_client_get_default();
+       if (gconf_client)
+       {
+               file_dir = gconf_client_get_string(gconf_client,
+                                                  ALTOS_DIR_PATH,
+                                                  NULL);
+               g_object_unref(G_OBJECT(gconf_client));
+       }
+       if (!file_dir) {
+               aoview_file_dir = aoview_fullname(getenv("HOME"), DEFAULT_DIR);
+               aoview_file_save_conf();
+       } else {
+               aoview_file_dir = strdup(file_dir);
+       }
+
+       file_chooser_dialog = GTK_FILE_CHOOSER(glade_xml_get_widget(xml, "file_chooser_dialog"));
+       assert(file_chooser_dialog);
+       gtk_file_chooser_set_filename(file_chooser_dialog, aoview_file_dir);
+
+       file_configure_ok = glade_xml_get_widget(xml, "file_configure_ok");
+       assert(file_configure_ok);
+
+       g_signal_connect(G_OBJECT(file_configure_ok), "clicked",
+                        G_CALLBACK(aoview_file_configure),
+                        file_chooser_dialog);
+
+
+       file_fail_dialog = GTK_MESSAGE_DIALOG(glade_xml_get_widget(xml, "file_fail_dialog"));
+       assert(file_fail_dialog);
+}
diff --git a/aoview/aoview_log.c b/aoview/aoview_log.c
new file mode 100644 (file)
index 0000000..1b89c28
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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 "aoview.h"
+
+static struct aoview_file      *aoview_log;
+
+void
+aoview_log_new(void)
+{
+       aoview_file_finish(aoview_log);
+       aoview_state_new();
+}
+
+void
+aoview_log_set_serial(int serial)
+{
+       aoview_file_set_serial(aoview_log, serial);
+}
+
+int
+aoview_log_get_serial(void)
+{
+       return aoview_file_get_serial(aoview_log);
+}
+
+void
+aoview_log_printf(char *format, ...)
+{
+       va_list ap;
+
+       va_start(ap, format);
+       aoview_file_vprintf(aoview_log, format, ap);
+       va_end(ap);
+}
+
+static void
+aoview_log_new_item(GtkWidget *widget, gpointer data)
+{
+       aoview_file_finish(aoview_log);
+}
+
+void
+aoview_log_init(GladeXML *xml)
+{
+       GtkWidget       *log_new;
+
+       aoview_log = aoview_file_new("telem");
+       assert(aoview_log);
+
+       log_new = glade_xml_get_widget(xml, "log_new");
+       assert(log_new);
+       g_signal_connect(G_OBJECT(log_new), "activate",
+                        G_CALLBACK(aoview_log_new_item),
+                        NULL);
+}
diff --git a/aoview/aoview_main.c b/aoview/aoview_main.c
new file mode 100644 (file)
index 0000000..4590751
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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 "aoview.h"
+
+static const char aoview_glade[] = {
+#include "aoview_glade.h"
+};
+
+static void usage(void) {
+       printf("aoview [--device|-d device_file]");
+       exit(1);
+}
+
+static void destroy_event(GtkWidget *widget, gpointer data)
+{
+       gtk_main_quit();
+}
+
+int main(int argc, char **argv)
+{
+       GladeXML *xml = NULL;
+       GtkWidget *mainwindow;
+       char *device = NULL;
+       GtkAboutDialog *about_dialog;
+
+       static struct option long_options[] = {
+               { "device", 1, 0, 'd'},
+               { 0, 0, 0, 0 }
+       };
+       for (;;) {
+               int c, temp;
+
+               c = getopt_long_only(argc, argv, "d:", long_options, &temp);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'd':
+                       device = optarg;
+                       break;
+               default:
+                       usage();
+               }
+       }
+
+       gtk_init(&argc, &argv);
+       glade_init();
+
+       xml = glade_xml_new_from_buffer(aoview_glade, sizeof (aoview_glade), NULL, NULL);
+
+       /* connect the signals in the interface */
+       glade_xml_signal_autoconnect(xml);
+
+       /* Hook up the close button. */
+       mainwindow = glade_xml_get_widget(xml, "aoview");
+       assert(mainwindow);
+
+       g_signal_connect (G_OBJECT(mainwindow), "destroy",
+           G_CALLBACK(destroy_event), NULL);
+
+       about_dialog = GTK_ABOUT_DIALOG(glade_xml_get_widget(xml, "about_dialog"));
+       assert(about_dialog);
+       gtk_about_dialog_set_version(about_dialog, AOVIEW_VERSION);
+
+       aoview_dev_dialog_init(xml);
+
+       aoview_state_init(xml);
+
+       aoview_file_init(xml);
+
+       aoview_log_init(xml);
+
+       aoview_table_init(xml);
+
+       aoview_eeprom_init(xml);
+
+       gtk_main();
+
+       return 0;
+}
diff --git a/aoview/aoview_monitor.c b/aoview/aoview_monitor.c
new file mode 100644 (file)
index 0000000..e2ba75b
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * 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 "aoview.h"
+
+static struct aoview_serial *monitor_serial;
+
+#define MONITOR_LEN    1024
+
+static char    monitor_line[MONITOR_LEN + 1];
+static int     monitor_pos;
+
+void
+aoview_monitor_disconnect(void)
+{
+       if (monitor_serial) {
+               aoview_serial_close(monitor_serial);
+               monitor_serial = NULL;
+       }
+       aoview_table_clear();
+       aoview_log_new();
+}
+
+static void
+aoview_parse_string(char *target, int len, char *source)
+{
+       strncpy(target, source, len-1);
+       target[len-1] = '\0';
+}
+
+static void
+aoview_parse_int(int *target, char *source)
+{
+       *target = strtol(source, NULL, 0);
+}
+
+static void
+aoview_parse_pos(double *target, char *source)
+{
+       int     deg;
+       double  min;
+       char    dir;
+       double  r;
+
+       if (sscanf(source, "%d°%lf'%c", &deg, &min, &dir) != 3) {
+               *target = 0;
+               return;
+       }
+       r = deg + min / 60.0;
+       if (dir == 'S' || dir == 'W')
+               r = -r;
+       *target = r;
+}
+
+static void
+aoview_monitor_parse(char *line)
+{
+       char *saveptr;
+       char *words[64];
+       int nword;
+       struct aostate  state;
+
+       if (aoview_log_get_serial())
+               aoview_log_printf ("%s\n", line);
+       for (nword = 0; nword < 64; nword++) {
+               words[nword] = strtok_r(line, " \t\n", &saveptr);
+               line = NULL;
+               if (words[nword] == NULL)
+                       break;
+       }
+       if (nword < 36)
+               return;
+       if (strcmp(words[0], "CALL") != 0)
+               return;
+       aoview_parse_string(state.callsign, sizeof (state.callsign), words[1]);
+       aoview_parse_int(&state.serial, words[3]);
+       aoview_log_set_serial(state.serial);
+
+       aoview_parse_int(&state.rssi, words[5]);
+       aoview_parse_string(state.state, sizeof (state.state), words[9]);
+       aoview_parse_int(&state.tick, words[10]);
+       aoview_parse_int(&state.accel, words[12]);
+       aoview_parse_int(&state.pres, words[14]);
+       aoview_parse_int(&state.temp, words[16]);
+       aoview_parse_int(&state.batt, words[18]);
+       aoview_parse_int(&state.drogue, words[20]);
+       aoview_parse_int(&state.main, words[22]);
+       aoview_parse_int(&state.flight_accel, words[24]);
+       aoview_parse_int(&state.ground_accel, words[26]);
+       aoview_parse_int(&state.flight_vel, words[28]);
+       aoview_parse_int(&state.flight_pres, words[30]);
+       aoview_parse_int(&state.ground_pres, words[32]);
+       aoview_parse_int(&state.nsat, words[34]);
+       if (strcmp (words[36], "unlocked") != 0 && nword >= 40) {
+               state.locked = 1;
+               sscanf(words[36], "%d:%d:%d", &state.gps_time.hour, &state.gps_time.minute, &state.gps_time.second);
+               aoview_parse_pos(&state.lat, words[37]);
+               aoview_parse_pos(&state.lon, words[38]);
+               sscanf(words[39], "%dm", &state.alt);
+       } else {
+               state.locked = 0;
+               state.gps_time.hour = state.gps_time.minute = state.gps_time.second = 0;
+               state.lat = state.lon = 0;
+               state.alt = 0;
+       }
+       aoview_state_notify(&state);
+}
+
+static void
+aoview_monitor_callback(gpointer user_data,
+                       struct aoview_serial *serial,
+                       gint revents)
+{
+       int     c;
+
+       if (revents & (G_IO_HUP|G_IO_ERR)) {
+               aoview_monitor_disconnect();
+               return;
+       }
+       if (revents & G_IO_IN) {
+               for (;;) {
+                       c = aoview_serial_getc(serial);
+                       if (c == -1)
+                               break;
+                       if (c == '\r')
+                               continue;
+                       if (c == '\n') {
+                               monitor_line[monitor_pos] = '\0';
+                               if (monitor_pos)
+                               aoview_monitor_parse(monitor_line);
+                               monitor_pos = 0;
+                       } else if (monitor_pos < MONITOR_LEN)
+                               monitor_line[monitor_pos++] = c;
+               }
+       }
+}
+
+gboolean
+aoview_monitor_connect(char *tty)
+{
+       aoview_monitor_disconnect();
+       monitor_serial = aoview_serial_open(tty);
+       if (!monitor_serial)
+               return FALSE;
+       aoview_serial_set_callback(monitor_serial,
+                                  aoview_monitor_callback,
+                                  monitor_serial,
+                                  NULL);
+       return TRUE;
+}
diff --git a/aoview/aoview_serial.c b/aoview/aoview_serial.c
new file mode 100644 (file)
index 0000000..1d8fefc
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * 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 "aoview.h"
+#include <termios.h>
+
+#define AOVIEW_SERIAL_IN_BUF   64
+#define AOVIEW_SERIAL_OUT_BUF  64
+
+struct aoview_buf {
+       char            *buf;
+       int             off;
+       int             count;
+       int             size;
+};
+
+static int
+aoview_buf_write(struct aoview_buf *buf, char *data, int len)
+{
+       if (buf->count + len > buf->size) {
+               int     new_size = buf->size * 2;
+               if (new_size == 0)
+                       new_size = 1024;
+               if (buf->buf)
+                       buf->buf = realloc (buf->buf, new_size);
+               else
+                       buf->buf = malloc (new_size);
+               buf->size = new_size;
+       }
+       memcpy(buf->buf + buf->count, data, len);
+       buf->count += len;
+       return len;
+}
+
+static int
+aoview_buf_read(struct aoview_buf *buf, char *data, int len)
+{
+       if (len > buf->count - buf->off)
+               len = buf->count - buf->off;
+       memcpy (data, buf->buf + buf->off, len);
+       buf->off += len;
+       if (buf->off == buf->count)
+               buf->off = buf->count = 0;
+       return len;
+}
+
+static int
+aoview_buf_getc(struct aoview_buf *buf)
+{
+       char    b;
+       int     r;
+
+       r = aoview_buf_read(buf, &b, 1);
+       if (r == 1)
+               return (int) b;
+       return -1;
+}
+
+static void
+aoview_buf_flush(struct aoview_buf *buf, int fd)
+{
+       int     ret;
+
+       if (buf->count > buf->off) {
+               ret = write(fd, buf->buf + buf->off, buf->count - buf->off);
+               if (ret > 0) {
+                       buf->off += ret;
+                       if (buf->off == buf->count)
+                               buf->off = buf->count = 0;
+               }
+       }
+}
+
+static void
+aoview_buf_fill(struct aoview_buf *buf, int fd)
+{
+       int ret;
+
+       while (buf->count >= buf->size) {
+               int new_size = buf->size * 2;
+               buf->buf = realloc (buf->buf, new_size);
+               buf->size = new_size;
+       }
+
+       ret = read(fd, buf->buf + buf->count, buf->size - buf->count);
+       if (ret > 0)
+               buf->count += ret;
+}
+
+static void
+aoview_buf_init(struct aoview_buf *buf)
+{
+       buf->buf = malloc (buf->size = 1024);
+       buf->count = 0;
+}
+
+static void
+aoview_buf_fini(struct aoview_buf *buf)
+{
+       free(buf->buf);
+}
+
+struct aoview_serial {
+       GSource                 source;
+       int                     fd;
+       struct termios          save_termios;
+       struct aoview_buf       in_buf;
+       struct aoview_buf       out_buf;
+       GPollFD                 poll_fd;
+};
+
+
+void
+aoview_serial_printf(struct aoview_serial *serial, char *format, ...)
+{
+       char    buf[1024];
+       va_list ap;
+       int     ret;
+
+       /* sprintf to a local buffer */
+       va_start(ap, format);
+       ret = vsnprintf(buf, sizeof(buf), format, ap);
+       va_end(ap);
+       if (ret > sizeof(buf)) {
+               fprintf(stderr, "printf overflow for format %s\n",
+                       format);
+       }
+
+       /* flush local buffer to the wire */
+       aoview_buf_write(&serial->out_buf, buf, ret);
+       aoview_buf_flush(&serial->out_buf, serial->fd);
+}
+
+int
+aoview_serial_read(struct aoview_serial *serial, char *buf, int len)
+{
+       return aoview_buf_read(&serial->in_buf, buf, len);
+}
+
+int
+aoview_serial_getc(struct aoview_serial *serial)
+{
+       return aoview_buf_getc(&serial->in_buf);
+}
+
+static gboolean
+serial_prepare(GSource *source, gint *timeout)
+{
+       struct aoview_serial *serial = (struct aoview_serial *) source;
+       *timeout = -1;
+
+       if (serial->out_buf.count)
+               serial->poll_fd.events |= G_IO_OUT;
+       else
+               serial->poll_fd.events &= ~G_IO_OUT;
+       return FALSE;
+}
+
+static gboolean
+serial_check(GSource *source)
+{
+       struct aoview_serial *serial = (struct aoview_serial *) source;
+       gint revents = serial->poll_fd.revents;
+
+       if (revents & G_IO_NVAL)
+               return FALSE;
+       if (revents & G_IO_IN)
+               return TRUE;
+       if (revents & G_IO_OUT)
+               return TRUE;
+       return FALSE;
+}
+
+static gboolean
+serial_dispatch(GSource *source,
+               GSourceFunc callback,
+               gpointer user_data)
+{
+       struct aoview_serial *serial = (struct aoview_serial *) source;
+       aoview_serial_callback func = (aoview_serial_callback) callback;
+       gint revents = serial->poll_fd.revents;
+
+       if (revents & G_IO_IN)
+               aoview_buf_fill(&serial->in_buf, serial->fd);
+
+       if (revents & G_IO_OUT)
+               aoview_buf_flush(&serial->out_buf, serial->fd);
+
+       if (func)
+               (*func)(user_data, serial, revents);
+       return TRUE;
+}
+
+static void
+serial_finalize(GSource *source)
+{
+       struct aoview_serial *serial = (struct aoview_serial *) source;
+
+       aoview_buf_fini(&serial->in_buf);
+       aoview_buf_fini(&serial->out_buf);
+       tcsetattr(serial->fd, TCSAFLUSH, &serial->save_termios);
+       close (serial->fd);
+}
+
+static GSourceFuncs serial_funcs = {
+       serial_prepare,
+       serial_check,
+       serial_dispatch,
+       serial_finalize
+};
+
+struct aoview_serial *
+aoview_serial_open(const char *tty)
+{
+       struct aoview_serial    *serial;
+       struct termios  termios;
+
+       serial = (struct aoview_serial *) g_source_new(&serial_funcs, sizeof (struct aoview_serial));
+       aoview_buf_init(&serial->in_buf);
+       aoview_buf_init(&serial->out_buf);
+       serial->fd = open (tty, O_RDWR | O_NONBLOCK);
+       if (serial->fd < 0) {
+               free (serial);
+               return NULL;
+       }
+       tcgetattr(serial->fd, &termios);
+       serial->save_termios = termios;
+       cfmakeraw(&termios);
+       tcsetattr(serial->fd, TCSAFLUSH, &termios);
+
+       aoview_serial_printf(serial, "E 0\n");
+       tcdrain(serial->fd);
+       usleep(15*1000);
+       tcflush(serial->fd, TCIFLUSH);
+       serial->poll_fd.fd = serial->fd;
+       serial->poll_fd.events = G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR;
+       g_source_attach(&serial->source, NULL);
+       g_source_add_poll(&serial->source,&serial->poll_fd);
+       return serial;
+}
+
+void
+aoview_serial_close(struct aoview_serial *serial)
+{
+       g_source_remove_poll(&serial->source, &serial->poll_fd);
+       g_source_destroy(&serial->source);
+       g_source_unref(&serial->source);
+       free(serial);
+}
+
+void
+aoview_serial_set_callback(struct aoview_serial *serial,
+                          aoview_serial_callback func,
+                          gpointer data,
+                          GDestroyNotify notify)
+{
+       g_source_set_callback(&serial->source, (GSourceFunc) func, data, notify);
+}
diff --git a/aoview/aoview_state.c b/aoview/aoview_state.c
new file mode 100644 (file)
index 0000000..356828c
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * 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 "aoview.h"
+#include <math.h>
+
+static double  pad_lat_total;
+static double  pad_lon_total;
+static int     pad_alt_total;
+static int     npad_gps;
+static int     prev_tick;
+static double  prev_accel;
+static double  pad_lat;
+static double  pad_lon;
+static double  pad_alt;
+static double  min_pres;
+static double  min_accel;
+
+#define NUM_PAD_SAMPLES        10
+
+static void
+aoview_great_circle (double start_lat, double start_lon,
+                    double end_lat, double end_lon,
+                    double *dist, double *bearing)
+{
+       double rad = M_PI / 180;
+       double earth_radius = 6371.2;
+       double lat1 = rad * start_lat;
+       double lon1 = -rad * start_lon;
+       double lat2 = rad * end_lat;
+       double lon2 = -rad * end_lon;
+
+       double d = acos(sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos(lon1-lon2));
+       double argacos = (sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1));
+       double crs;
+       if (sin(lon2-lon1) < 0)
+               crs = acos(argacos);
+       else
+               crs = 2 * M_PI - acos(argacos);
+       *dist = d * earth_radius;
+       *bearing = crs * 180/M_PI;
+}
+
+static void
+aoview_state_add_deg(char *label, double deg, char pos, char neg)
+{
+       double  int_part;
+       double  min;
+       char    sign = pos;
+
+       if (deg < 0) {
+               deg = -deg;
+               sign = neg;
+       }
+       int_part = floor (deg);
+       min = (deg - int_part) * 60.0;
+       aoview_table_add_row(label, "%d°%lf'%c",
+                            (int) int_part, min, sign);
+
+}
+
+void
+aoview_state_notify(struct aostate *state)
+{
+       int     altitude;
+       double  accel;
+       int     ticks;
+       double  dist;
+       double  bearing;
+       double  temp;
+       double  velocity;
+       double  battery;
+       double  drogue_sense, main_sense;
+       double  max_accel;
+
+       if (!strcmp(state->state, "pad")) {
+               if (state->locked && npad_gps < NUM_PAD_SAMPLES) {
+                       pad_lat_total += state->lat;
+                       pad_lon_total += state->lon;
+                       pad_alt_total += state->alt;
+                       npad_gps++;
+               }
+               if (state->locked && npad_gps <= NUM_PAD_SAMPLES) {
+                       pad_lat = pad_lat_total / npad_gps;
+                       pad_lon = pad_lon_total / npad_gps;
+                       pad_alt = pad_alt_total / npad_gps;
+               }
+               min_pres = state->ground_pres;
+               min_accel = state->ground_accel;
+       }
+       if (state->flight_pres < min_pres)
+               min_pres = state->flight_pres;
+       if (state->flight_accel < min_accel)
+               min_accel = state->flight_accel;
+       altitude = aoview_pres_to_altitude(state->flight_pres) - aoview_pres_to_altitude(state->ground_pres);
+       accel = (state->ground_accel - state->flight_accel) / 27.0;
+       velocity = state->flight_vel / 2700.0;
+       max_accel = (state->ground_accel - min_accel) / 27.0;
+       ticks = state->tick - prev_tick;
+       temp = ((state->temp / 32767.0 * 3.3) - 0.5) / 0.01;
+       battery = (state->batt / 32767.0 * 5.0);
+       drogue_sense = (state->drogue / 32767.0 * 15.0);
+       main_sense = (state->main / 32767.0 * 15.0);
+
+       prev_accel = accel;
+       prev_tick = state->tick;
+       aoview_table_start();
+
+       if (npad_gps >= NUM_PAD_SAMPLES)
+               aoview_table_add_row("Ground state", "ready");
+       else
+               aoview_table_add_row("Ground state", "waiting for gps (%d)",
+                                    NUM_PAD_SAMPLES - npad_gps);
+       aoview_table_add_row("Rocket state", "%s", state->state);
+       aoview_table_add_row("Callsign", "%s", state->callsign);
+       aoview_table_add_row("Rocket serial", "%d", state->serial);
+
+       aoview_table_add_row("RSSI", "%ddBm", state->rssi);
+       aoview_table_add_row("Height", "%dm", altitude);
+       aoview_table_add_row("Max height", "%dm",
+                            aoview_pres_to_altitude(min_pres) -
+                            aoview_pres_to_altitude(state->ground_pres));
+       aoview_table_add_row("Acceleration", "%gm/s²", accel);
+       aoview_table_add_row("Max acceleration", "%gm/s²", max_accel);
+       aoview_table_add_row("Velocity", "%gm/s", velocity);
+       aoview_table_add_row("Temperature", "%g°C", temp);
+       aoview_table_add_row("Battery", "%gV", battery);
+       aoview_table_add_row("Drogue", "%gV", drogue_sense);
+       aoview_table_add_row("Main", "%gV", main_sense);
+       aoview_table_add_row("Pad altitude", "%dm", aoview_pres_to_altitude(state->ground_pres));
+       aoview_table_add_row("Satellites", "%d", state->nsat);
+       if (state->locked) {
+               aoview_state_add_deg("Latitude", state->lat, 'N', 'S');
+               aoview_state_add_deg("Longitude", state->lon, 'E', 'W');
+               aoview_table_add_row("GPS alt", "%d", state->alt);
+               aoview_table_add_row("GPS time", "%02d:%02d:%02d",
+                                    state->gps_time.hour,
+                                    state->gps_time.minute,
+                                    state->gps_time.second);
+               aoview_great_circle(pad_lat, pad_lon, state->lat, state->lon,
+                                   &dist, &bearing);
+               aoview_table_add_row("Distance from pad", "%gm", dist * 1000);
+               aoview_table_add_row("Direction from pad", "%g°", bearing);
+       } else {
+               aoview_table_add_row("GPS", "unlocked");
+       }
+       if (npad_gps) {
+               aoview_state_add_deg("Pad latitude", pad_lat, 'N', 'S');
+               aoview_state_add_deg("Pad longitude", pad_lon, 'E', 'W');
+               aoview_table_add_row("Pad GPS alt", "%gm", pad_alt);
+       }
+       aoview_table_finish();
+}
+
+void
+aoview_state_new(void)
+{
+       pad_lat_total = 0;
+       pad_lon_total = 0;
+       pad_alt_total = 0;
+       npad_gps = 0;
+       prev_tick = 0;
+       prev_accel = 0;
+       pad_lat = 0;
+       pad_lon = 0;
+       pad_alt = 0;
+       min_pres = 32767;
+       min_accel = 32767;
+}
+
+void
+aoview_state_init(GladeXML *xml)
+{
+       aoview_state_new();
+}
diff --git a/aoview/aoview_table.c b/aoview/aoview_table.c
new file mode 100644 (file)
index 0000000..b3fc6a4
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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 "aoview.h"
+
+static GtkTreeView     *dataview;
+static GtkListStore    *datalist;
+
+void
+aoview_table_start(void)
+{
+       datalist = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
+}
+
+void
+aoview_table_add_row(char *label, char *format, ...)
+{
+       char            buf[1024];
+       va_list         ap;
+       GtkTreeIter     iter;
+
+       va_start(ap, format);
+       vsnprintf(buf, sizeof (buf), format, ap);
+       va_end(ap);
+       gtk_list_store_append(datalist, &iter);
+       gtk_list_store_set(datalist, &iter,
+                          0, label,
+                          1, buf,
+                          -1);
+}
+
+void
+aoview_table_finish(void)
+{
+       gtk_tree_view_set_model(dataview, GTK_TREE_MODEL(datalist));
+       g_object_unref(G_OBJECT(datalist));
+       gtk_tree_view_columns_autosize(dataview);
+}
+
+void
+aoview_table_clear(void)
+{
+       gtk_tree_view_set_model(dataview, NULL);
+}
+
+void
+aoview_table_init(GladeXML *xml)
+{
+       dataview = GTK_TREE_VIEW(glade_xml_get_widget(xml, "dataview"));
+       assert(dataview);
+
+       aoview_add_plain_text_column(dataview, "Field", 0, 20);
+       aoview_add_plain_text_column(dataview, "Value", 1, 32);
+}
diff --git a/aoview/aoview_util.c b/aoview/aoview_util.c
new file mode 100644 (file)
index 0000000..6ea62ac
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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 "aoview.h"
+
+char *
+aoview_fullname (char *dir, char *file)
+{
+       char    *new;
+       int     dlen = strlen (dir);
+       int     flen = strlen (file);
+       int     slen = 0;
+
+       if (dir[dlen-1] != '/')
+               slen = 1;
+       new = malloc (dlen + slen + flen + 1);
+       if (!new)
+               return 0;
+       strcpy(new, dir);
+       if (slen)
+               strcat (new, "/");
+       strcat(new, file);
+       return new;
+}
+
+char *
+aoview_basename(char *file)
+{
+       char *b;
+
+       b = strrchr(file, '/');
+       if (!b)
+               return file;
+       return b + 1;
+}
+
+int
+aoview_mkdir(char *dir)
+{
+       char    *slash;
+       char    *d;
+       char    *part;
+
+       d = dir;
+       for (;;) {
+               slash = strchr (d, '/');
+               if (!slash)
+                       slash = d + strlen(d);
+               if (!*slash)
+                       break;
+               part = strndup(dir, slash - dir);
+               if (!access(part, F_OK))
+                       if (mkdir(part, 0777) < 0)
+                               return -errno;
+               free(part);
+               d = slash + 1;
+       }
+       return 0;
+}
+
+GtkTreeViewColumn *
+aoview_add_plain_text_column (GtkTreeView *view, const gchar *title, gint model_column, gint width)
+{
+       GtkCellRenderer *renderer;
+       GtkTreeViewColumn *column;
+
+       renderer = gtk_cell_renderer_text_new ();
+       g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_NONE, NULL);
+       g_object_set(renderer, "width-chars", width, NULL);
+       column = gtk_tree_view_column_new_with_attributes (title, renderer,
+                                                          "text", model_column,
+                                                          NULL);
+       gtk_tree_view_column_set_resizable (column, FALSE);
+       gtk_tree_view_append_column (view, column);
+
+       return column;
+}
diff --git a/aoview/design b/aoview/design
new file mode 100644 (file)
index 0000000..6ec2ea7
--- /dev/null
@@ -0,0 +1,27 @@
+Requirements:
+       real-time display of telemetry
+       off-line display of logged data
+       Logging of telemetry
+       Capture of logged data to disk
+
+Input data:
+       accelerometer
+       barometer
+       thermometer
+       gps
+       drogue and main continuity
+       battery voltage
+       time
+       reported flight state
+       reported events
+
+Computed data:
+       velocity (from accelerometer)
+       altitude
+       range
+       direction
+
+Displays:
+       numeric display of current rocket status
+       (graphics come later)
+       text message log
index 3e220914080341e71cde1511a46de0bd6e9907b2..5f7708fd2f8c93ac4b1d8da40fefc0baaa71b2ca 100644 (file)
@@ -48,12 +48,12 @@ main (int argc, char **argv)
                fprintf(stderr, "image create failed\n");
                exit (1);
        }
-       
+
        ccdbg_hex_file_free(hex);
        dbg = ccdbg_open();
        if (!dbg)
                exit (1);
-       
+
        ccdbg_add_debug(CC_DEBUG_FLASH);
 
        ccdbg_debug_mode(dbg);
index 402d9b1333d99e4c3dca8e0d0bef6ced23d189c1..7090c9a364dbca0f35bf7f5370537464cefb5839 100644 (file)
@@ -26,7 +26,7 @@ main (int argc, char **argv)
        dbg = ccdbg_open();
        if (!dbg)
                exit (1);
-       
+
        ccdbg_add_debug(CC_DEBUG_BITBANG);
 
        ccdbg_manual(dbg, stdin);
index 6c8963c4f7c86437e5fdeb0092305c732df3147c..99511a6e0a19b9b2915b1b72cd3b8c14caaf7cd1 100644 (file)
@@ -1,16 +1,16 @@
-dnl 
-dnl  Copyright © 2008 Keith Packard <keithp@keithp.com>
-dnl 
+dnl
+dnl  Copyright © 2008,2009 Keith Packard <keithp@keithp.com>
+dnl
 dnl  This program is free software; you can redistribute it and/or modify
 dnl  it under the terms of the GNU General Public License as published by
 dnl  the Free Software Foundation; either version 2 of the License, or
 dnl  (at your option) any later version.
-dnl 
+dnl
 dnl  This program is distributed in the hope that it will be useful, but
 dnl  WITHOUT ANY WARRANTY; without even the implied warranty of
 dnl  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 dnl  General Public License for more details.
-dnl 
+dnl
 dnl  You should have received a copy of the GNU General Public License along
 dnl  with this program; if not, write to the Free Software Foundation, Inc.,
 dnl  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
@@ -19,7 +19,7 @@ dnl Process this file with autoconf to create configure.
 
 AC_INIT(COPYING)
 
-AM_INIT_AUTOMAKE(cctools, 0.1)
+AM_INIT_AUTOMAKE(altos, 0.1)
 AM_MAINTAINER_MODE
 
 dnl ==========================================================================
@@ -43,57 +43,13 @@ if test "x$GCC" = "xyes"; then
 fi
 AC_SUBST(WARN_CFLAGS)
 
-dnl ==========================================================================
-
-AM_CONDITIONAL(CROSS_COMPILING, test $cross_compiling = yes)
-
-dnl ==========================================================================
-
-# Setup for compiling build tools (fc-glyphname, etc)
-AC_MSG_CHECKING([for a C compiler for build tools])
-if test $cross_compiling = yes; then
-  AC_CHECK_PROGS(CC_FOR_BUILD, gcc cc)
-else
-  CC_FOR_BUILD=$CC
-fi
-AC_MSG_RESULT([$CC_FOR_BUILD])
-AC_SUBST(CC_FOR_BUILD)
+PKG_CHECK_MODULES([GNOME], [gtk+-2.0 libglade-2.0 gconf-2.0])
 
 PKG_CHECK_MODULES([LIBUSB], [libusb-1.0])
 
-AC_MSG_CHECKING([for suffix of executable build tools])
-if test $cross_compiling = yes; then
-  cat >conftest.c <<\_______EOF
-int
-main ()
-{
-  exit (0);
-}
-_______EOF
-  for i in .exe ""; do
-    compile="$CC_FOR_BUILD conftest.c -o conftest$i"
-    if AC_TRY_EVAL(compile); then
-      if (./conftest) 2>&AC_FD_CC; then
-       EXEEXT_FOR_BUILD=$i
-       break
-      fi
-    fi
-  done
-  rm -f conftest*
-  if test "${EXEEXT_FOR_BUILD+set}" != set; then
-    AC_MSG_ERROR([Cannot determine suffix of executable build tools])
-  fi
-else
-  EXEEXT_FOR_BUILD=$EXEEXT
-fi
-AC_MSG_RESULT([$EXEEXT_FOR_BUILD])
-AC_SUBST(EXEEXT_FOR_BUILD)
-
-USB_LIBS="-lusb"
-AC_SUBST(USB_LIBS)
-
 AC_OUTPUT([
-Makefile 
+Makefile
+aoview/Makefile
 lib/Makefile
 ccload/Makefile
 s51/Makefile
index a5d2d369e139db6226a44a47dc4ad552ec3ebd33..1d3ba47664af4bf19cac9a29452eca02e49133c8 100644 (file)
@@ -60,13 +60,13 @@ void
 cc_bitbang_wait_reset(struct cc_bitbang *bb)
 {
        struct timespec req, rem;
-       
+
        cc_bitbang_sync(bb);
        req.tv_sec = (cc_reset_us) / 1000000;
        req.tv_nsec = ((cc_reset_us) % 1000000) * 1000;
        nanosleep(&req, &rem);
 }
-       
+
 struct cc_bitbang *
 cc_bitbang_open(void)
 {
@@ -267,4 +267,3 @@ cc_bitbang_recv_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes)
                first = 0;
        }
 }
-
index 2efe572ed701043340b8030b94cd4190085bd7ce..dc764c24e99f79fd326226cbb8f795063ab58340 100644 (file)
@@ -77,14 +77,14 @@ cc_handle_in(struct cc_usb *cc)
        uint8_t h, l;
        int     in_pos;
        int     read_pos;
-       
+
        in_pos = 0;
        read_pos = 0;
        while (read_pos < cc->read_count && in_pos < cc->in_count) {
                /*
                 * Skip to next hex character
                 */
-               while (in_pos < cc->in_count && 
+               while (in_pos < cc->in_count &&
                       cc_hex_nibble(cc->in_buf[in_pos]) == NOT_HEX)
                        in_pos++;
                /*
@@ -109,7 +109,7 @@ cc_handle_in(struct cc_usb *cc)
                if (--cc->read_buf[read_pos].len <= 0)
                        read_pos++;
        }
-       
+
        /* Move remaining bytes to the start of the input buffer */
        if (in_pos) {
                memmove(cc->in_buf, cc->in_buf + in_pos,
@@ -213,7 +213,7 @@ cc_usb_printf(struct cc_usb *cc, char *format, ...)
        char    buf[1024], *b;
        va_list ap;
        int     ret, this_time;
-       
+
        /* sprintf to a local buffer */
        va_start(ap, format);
        ret = vsnprintf(buf, sizeof(buf), format, ap);
@@ -243,7 +243,7 @@ cc_usb_send_bytes(struct cc_usb *cc, uint8_t *bytes, int len)
 {
        int     this_len;
        int     ret = len;
-       
+
        while (len) {
                this_len = len;
                if (this_len > 8)
@@ -327,7 +327,7 @@ cc_usb_open(char *tty)
 {
        struct cc_usb   *cc;
        struct termios  termios;
-       
+
        if (!tty)
                tty = DEFAULT_TTY;
        cc = calloc (sizeof (struct cc_usb), 1);
@@ -357,4 +357,3 @@ cc_usb_close(struct cc_usb *cc)
        close (cc->fd);
        free (cc);
 }
-
index 7d1ae067556ee2dd2343566e7454a540409760c3..a1002879f815b178630face7a11ff8e365440350 100644 (file)
@@ -161,7 +161,7 @@ ccdbg_execute_hex_image(struct ccdbg *dbg, struct hex_image *image)
 {
        uint16_t pc;
        uint8_t status;
-       
+
        if (image->address < 0xf000) {
                fprintf(stderr, "Cannot execute program starting at 0x%04x\n", image->address);
                return -1;
@@ -174,4 +174,3 @@ ccdbg_execute_hex_image(struct ccdbg *dbg, struct hex_image *image)
        ccdbg_debug(CC_DEBUG_EXECUTE, "resume status: 0x%02x\n", status);
        return 0;
 }
-
index 8a586a21ccb4fc076da2886881d9830662736925..3e6729851502ff8895a6e2088836284035f7702c 100644 (file)
@@ -37,10 +37,10 @@ static uint8_t flash_page[] = {
 
        MOV_Rn_data(7), 0,
 #define FLASH_WORDS_HIGH       16
-       
+
        MOV_Rn_data(6), 0,
 #define FLASH_WORDS_LOW                18
-       
+
        MOV_direct_data, FWT, 0x20,
 #define FLASH_TIMING           21
 
@@ -76,7 +76,7 @@ static uint8_t flash_page[] = {
 static uint8_t flash_erase_page[] = {
        3,      MOV_direct_data, FADDRH, 0,
 #define ERASE_PAGE_HIGH        3
-       
+
        3,      MOV_direct_data, FADDRL, 0,
 #define ERASE_PAGE_LOW 7
 
@@ -107,7 +107,7 @@ ccdbg_flash_erase_page(struct ccdbg *dbg, uint16_t addr)
        uint8_t         status;
        uint8_t         old[0x10], new[0x10];
        int             i;
-       
+
        ccdbg_read_memory(dbg, addr, old, 0x10);
        flash_erase_page[ERASE_PAGE_HIGH] = page_addr >> 8;
        flash_erase_page[ERASE_PAGE_LOW] = page_addr & 0xff;
@@ -130,7 +130,7 @@ ccdbg_flash_erase_page(struct ccdbg *dbg, uint16_t addr)
 static uint8_t flash_write[] = {
        MOV_direct_data, P1DIR, 0x02,
        MOV_direct_data, P1,    0xFD,
-       
+
        MOV_A_direct, FCTL,
        JB,     ACC(FCTL_BUSY_BIT), 0xf1,
 
@@ -138,10 +138,10 @@ static uint8_t flash_write[] = {
 
        MOV_direct_data, FADDRH, 0,
 #define WRITE_PAGE_HIGH        16
-       
+
        MOV_direct_data, FADDRL, 0,
 #define WRITE_PAGE_LOW 19
-       
+
        MOV_direct_data, FCTL, FCTL_WRITE,
        MOV_direct_data, FWDATA, 0,
 #define WRITE_BYTE_0   25
@@ -267,7 +267,7 @@ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image)
        }
        ram_addr = 0xf000;
 
-       
+
        flash_prog = 0xf400;
 
        fwt = 0x20;
@@ -276,7 +276,7 @@ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image)
        ccdbg_debug(CC_DEBUG_FLASH, "Upload %d flash program bytes to 0x%04x\n",
               sizeof (flash_page), flash_prog);
        ccdbg_write_memory(dbg, flash_prog, flash_page, sizeof(flash_page));
-       
+
        remain = image->length;
        start = 0;
        while (remain) {
@@ -296,7 +296,7 @@ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image)
                        return 1;
                }
 #endif
-               
+
                flash_addr = image->address + start;
                flash_word_addr = flash_addr >> 1;
                flash_len = this_time + (this_time & 1);
@@ -304,11 +304,11 @@ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image)
 
                flash_words_low = flash_words & 0xff;
                flash_words_high = flash_words >> 8;
-               
+
                /* The flash code above is lame */
                if (flash_words_low)
                        flash_words_high++;
-       
+
                ccdbg_write_uint8(dbg, flash_prog + FLASH_ADDR_HIGH, flash_word_addr >> 8);
                ccdbg_write_uint8(dbg, flash_prog + FLASH_ADDR_LOW, flash_word_addr & 0xff);
 
@@ -336,7 +336,7 @@ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image)
                        fprintf(stderr, "flash page timed out\n");
                        return 1;
                }
-               
+
                ccdbg_debug(CC_DEBUG_FLASH, "Verify %d bytes in flash\n", this_time);
                ccdbg_read_memory(dbg, flash_addr, verify, this_time);
                if (memcmp (image->data + start, verify, this_time) != 0) {
index 86478da07b8c5f262c6adfb675cccf6aa11f2528..dfea915601a74e6258d8c6427b885eaf300870c5 100644 (file)
@@ -147,7 +147,7 @@ ccdbg_hex_read_record(struct hex_input *input)
                        --nhexbytes;
                        if (nhexbytes != 0)
                                break;
-                       
+
                        switch (state) {
                        case read_length:
                                record = ccdbg_hex_alloc(hex);
@@ -261,7 +261,7 @@ ccdbg_hex_file_read(FILE *file, char *name)
                        goto bail;
                if (hex->nrecord == srecord) {
                        srecord *= 2;
-                       newhex = realloc(hex, 
+                       newhex = realloc(hex,
                                         sizeof (struct hex_file) +
                                         srecord * sizeof (struct hex_record *));
                        if (!newhex)
index 878c5f97b9199a715164845a31dd479914f81a4c..554ac637c6911491e61005ba76ca7932d8d06686 100644 (file)
@@ -127,7 +127,7 @@ struct hex_image *
 ccdbg_read_hex_image(struct ccdbg *dbg, uint16_t address, uint16_t length)
 {
        struct hex_image *image;
-       
+
        image = calloc(sizeof(struct hex_image) + length, 1);
        image->address = address;
        image->length = length;
@@ -169,7 +169,7 @@ uint8_t
 ccdbg_write_sfr(struct ccdbg *dbg, uint8_t addr, uint8_t *bytes, int nbytes)
 {
        int     i;
-       
+
        for (i = 0; i < nbytes; i++) {
                sfr_write[SFR_WRITE_ADDR] = addr + i;
                sfr_write[SFR_WRITE_DATA] = *bytes++;
index 4559b4e7bd0d3476133b39cb70c9a1a3d79816e2..71bed2200478b2f9b56a199f2a8e7a8ee87d523f 100644 (file)
@@ -45,7 +45,7 @@ ccdbg_rom_replace_xmem(struct ccdbg *dbg,
        struct hex_image *rom = dbg->rom;
        if (!rom)
                return 0;
-       
+
        if (rom->address < addr + nbytes && addr < rom->address + rom->length) {
                int     start, stop;
 
index fe0ea3a0192cf4721f7a741c32232bb499556afb..4a2e3b9f00c9222118f93386024a206d06ab5ffd 100644 (file)
@@ -229,10 +229,10 @@ ccdbg_get_chip_id(struct ccdbg *dbg);
 
 uint8_t
 ccdbg_execute(struct ccdbg *dbg, uint8_t *inst);
-       
+
 uint8_t
 ccdbg_set_pc(struct ccdbg *dbg, uint16_t pc);
-       
+
 uint8_t
 ccdbg_execute_hex_image(struct ccdbg *dbg, struct hex_image *image);
 
index 1fe09aad82f486f76a2a588eb3ed7c5b67ea377d..6539394b541a95ec4c2761d75d7a9c739e253048 100644 (file)
@@ -130,7 +130,7 @@ cp_usb_async_write(struct cp_usb_async *cp, uint8_t mask, uint8_t value)
                                  0x37e1,               /* value */
                                  gpio_set,             /* index */
                                  0);                   /* length */
-       
+
        libusb_fill_control_transfer(cp->packet[p].transfer,
                                     cp->handle,
                                     cp->packet[p].data,
@@ -163,7 +163,7 @@ cp_usb_async_read(struct cp_usb_async *cp, uint8_t *valuep)
                                  0x00c2,               /* value */
                                  0,                    /* index */
                                  1);                   /* length */
-       
+
        libusb_fill_control_transfer(cp->packet[p].transfer,
                                     cp->handle,
                                     cp->packet[p].data,
index d227b78c90922c848fb11260086ff5cf90c62410..530848db1cd50bbad8c014bab9019100d56c7f8d 100644 (file)
@@ -89,11 +89,11 @@ cp_usb_open(void)
        int interface;
        int ret;
        uint8_t gpio;
-       
+
        usb_init();
        usb_find_busses();
        usb_find_devices();
-       
+
        busses = usb_get_busses();
        for (bus = busses; bus; bus = bus->next) {
                for (dev = bus->devices; dev; dev = dev->next) {
index 77a9849330158042e2184fdac72b9e19e500691a..aba65cd0f5b3de8ecd56c5ada56e7a68db5a843e 100644 (file)
@@ -47,15 +47,14 @@ Load a file
 Execution control:
 
        run <start>             - run starting at <start>
-       run <start> <stop>      - set temporary bp at <stop> 
+       run <start> <stop>      - set temporary bp at <stop>
        run                     - continue
        next                    - step over calls(?)
        step                    - step one instruction
-       
+
        reset                   - reset the simulator
        res                     - synonym?
-       
+
 Error messages:
 
        start with "Error:"
-       
index 02ecdddd3dd714935eebd2c18aa1481147559f90..4f803060dbc801c17e68685ed9903762daa06ac2 100644 (file)
@@ -73,7 +73,7 @@ static void
 dump_bytes(uint8_t *memory, int length, uint16_t start, char *format)
 {
        int group, i;
-       
+
        for (group = 0; group < length; group += 8) {
                s51_printf(format, start + group);
                for (i = group; i < length && i < group + 8; i++)
@@ -97,7 +97,7 @@ command_di (int argc, char **argv)
        uint8_t memory[65536];
        uint8_t status;
        int length;
-       
+
        if (argc != 3)
                return command_error;
        if (parse_uint16(argv[1], &start) != command_success)
@@ -117,7 +117,7 @@ command_ds (int argc, char **argv)
        uint8_t memory[0x100];
        uint8_t status;
        int length;
-       
+
        if (argc != 3)
                return command_error;
        if (parse_uint8(argv[1], &start) != command_success)
@@ -137,7 +137,7 @@ command_dx (int argc, char **argv)
        uint8_t memory[65536];
        uint8_t status;
        int length;
-       
+
        if (argc != 3)
                return command_error;
        if (parse_uint16(argv[1], &start) != command_success)
@@ -171,7 +171,7 @@ command_set (int argc, char **argv)
        for (i = 0; i < len; i++)
                if (parse_uint8(argv[i+3], &data[i]) != command_success)
                        return command_error;
-       
+
        if (strcmp(argv[1], "xram") == 0) {
                ccdbg_write_memory(s51_dbg, address, data, len);
        } else if (strcmp(argv[1], "iram") == 0) {
@@ -205,7 +205,7 @@ command_file (int argc, char **argv)
        struct hex_file *hex;
        struct hex_image *image;
        FILE *file;
-       
+
        if (argc != 2)
                return command_error;
        file = fopen (argv[1], "r");
@@ -257,7 +257,7 @@ static void
 disable_breakpoint(int b)
 {
        uint8_t status;
-       
+
        status = ccdbg_set_hw_brkpnt(s51_dbg, b, 0, breakpoints[b].address);
        if (status != 0x00 && status != 0xff)
                s51_printf("disable_breakpoint status 0x%02x\n", status);
@@ -267,7 +267,7 @@ static void
 enable_breakpoint(int b)
 {
        uint8_t status;
-       
+
        status = ccdbg_set_hw_brkpnt(s51_dbg, b, 1, breakpoints[b].address);
        if (status != 0xff)
                s51_printf("enable_breakpoint status 0x%02x\n", status);
@@ -434,7 +434,7 @@ command_run (int argc, char **argv)
        uint16_t pc;
        uint8_t status;
        int b;
-       
+
        if (argv[1]) {
                result = parse_uint16(argv[1], &start);
                if (result != command_success)
@@ -497,7 +497,7 @@ command_load (int argc, char **argv)
        FILE *file;
        struct hex_file *hex;
        struct hex_image *image;
-       
+
        if (!filename)
                return command_error;
        file = fopen(filename, "r");
@@ -599,7 +599,7 @@ info_breakpoints(int argc, char **argv)
                        }
                return command_success;
        }
-       
+
 }
 
 static enum command_result
@@ -610,7 +610,7 @@ static struct command_function infos[] = {
                "List current breakpoints\n" },
        { "help",   "?",  info_help,    "help",
                "Print this list\n" },
-       
+
        { NULL, NULL, NULL, NULL, NULL },
 };
 
@@ -624,7 +624,7 @@ enum command_result
 command_info(int argc, char **argv)
 {
        struct command_function *func;
-       
+
        if (argc < 2)
                return command_error;
        func = command_string_to_function(infos, argv[1]);
@@ -644,7 +644,7 @@ cc_wait(void)
                        return command_success;
                }
                if (s51_interrupted || s51_check_input()) {
-                       
+
                        ccdbg_halt(s51_dbg);
                        status = ccdbg_read_status(s51_dbg);
                        cc_stopped(status);
@@ -652,4 +652,3 @@ cc_wait(void)
                }
        }
 }
-
index 46b97b0c8ca7039c25867f9caa297cc0d72f121f..4dbd4c6036ebd72e0182aba47ca6fd81e466e191 100644 (file)
@@ -137,7 +137,7 @@ main(int argc, char **argv)
                for (;;) {
                        struct sockaddr_in client_addr;
                        socklen_t client_len = sizeof (struct sockaddr_in);
-                       
+
                        s = accept(l, (struct sockaddr *)
                                   &client_addr, &client_len);
                        if (s < 0) {
@@ -233,8 +233,7 @@ s51_check_input(void)
        if (r > 0) {
                char line[256];
                (void) s51_read_line(line, sizeof (line));
-               return 1; 
+               return 1;
        }
        return 0;
 }
-
index aba454859b94394e8711b60d76a2b6fc8dc6c687..170c979dbed599a1f99d643ce0fda2dd31f66351 100644 (file)
@@ -112,7 +112,7 @@ command_string_to_function(struct command_function *functions, char *name)
                    !strcmp(name, functions[i].alias))
                        return &functions[i];
        return NULL;
-}    
+}
 
 enum command_result
 command_function_help(struct command_function *functions, int argc, char **argv)
@@ -176,7 +176,7 @@ command_help(int argc, char **argv)
 {
        return command_function_help(functions, argc, argv);
 }
-    
+
 void
 command_syntax_error(int argc, char **argv)
 {
@@ -239,4 +239,3 @@ command_read (void)
        ccdbg_close(s51_dbg);
        s51_printf("...\n");
 }
-
index c283950e9b4e69993788c2f585d6426286292abc..f2f59a5286a6709fb96f4a66c5984cc381f3e680 100644 (file)
--- a/s51/s51.1
+++ b/s51/s51.1
@@ -151,14 +151,14 @@ List the things you can get info on.
 This doesn't do anything and is present only to retain compatibility with
 the original 8051 emulator.
 .SH "BOARD BRINGUP DEBUGGING"
-.PP 
+.PP
 While the original purpose for this program was to connect the source
 debugger with the hardware, it can also be used as a low-level hex debugger
 all on its own. In particular, all of the cc1111 peripherals can be
 manipulated directly from the s51 command line.
 .IP "Starting s51"
 If the CP2103 is plugged in, and the CC1111 is connected correctly, the
-\'s51\' command itself should connect to the device without trouble. 
+\'s51\' command itself should connect to the device without trouble.
 Note that the CP2103 must have the GPIO pins configured correctly as well.
 .IP
 $ s51
diff --git a/src/25lc1024.h b/src/25lc1024.h
new file mode 100644 (file)
index 0000000..44e5238
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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_ */
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..3928136
--- /dev/null
@@ -0,0 +1,262 @@
+#
+# AltOS build
+#
+#
+CC=sdcc
+
+VERSION=$(shell git describe)
+
+CFLAGS=--model-small --debug --opt-code-speed
+
+LDFLAGS=--out-fmt-ihx --code-loc 0x0000 --code-size 0x8000 \
+       --xram-loc 0xf000 --xram-size 0xda2 --iram-size 0xff
+
+INC = \
+       ao.h \
+       cc1111.h \
+       altitude.h \
+       25lc1024.h
+
+#
+# Common AltOS sources
+#
+ALTOS_SRC = \
+       ao_cmd.c \
+       ao_dbg.c \
+       ao_dma.c \
+       ao_mutex.c \
+       ao_panic.c \
+       ao_task.c \
+       ao_timer.c \
+       _bp.c
+
+#
+# Shared AltOS drivers
+#
+ALTOS_DRIVER_SRC = \
+       ao_beep.c \
+       ao_config.c \
+       ao_led.c \
+       ao_radio.c \
+       ao_stdio.c \
+       ao_usb.c
+
+TELE_COMMON_SRC = \
+       ao_gps_print.c \
+       ao_state.c
+
+#
+# Receiver code
+#
+TELE_RECEIVER_SRC =\
+       ao_monitor.c \
+       ao_rssi.c
+
+#
+# Shared Tele drivers (on TeleMetrum, TeleTerra, TeleDongle)
+#
+
+TELE_DRIVER_SRC = \
+       ao_convert.c \
+       ao_gps.c \
+       ao_serial.c
+
+#
+# Drivers for partially-flled boards (TT, TD and TI)
+#
+TELE_FAKE_SRC = \
+       ao_adc_fake.c \
+       ao_ee_fake.c
+
+#
+# Drivers only on TeleMetrum
+#
+TM_DRIVER_SRC = \
+       ao_adc.c \
+       ao_ee.c \
+       ao_gps_report.c \
+       ao_ignite.c
+
+#
+# Tasks run on TeleMetrum
+#
+TM_TASK_SRC = \
+       ao_flight.c \
+       ao_log.c \
+       ao_report.c \
+       ao_telemetry.c
+
+TM_MAIN_SRC = \
+       ao_telemetrum.c
+
+#
+# All sources for TeleMetrum
+#
+TM_SRC = \
+       $(ALTOS_SRC) \
+       $(ALTOS_DRIVER_SRC) \
+       $(TELE_DRIVER_SRC) \
+       $(TELE_COMMON_SRC) \
+       $(TM_DRIVER_SRC) \
+       $(TM_TASK_SRC) \
+       $(TM_MAIN_SRC)
+
+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) \
+       $(TELE_FAKE_SRC) \
+       $(TI_MAIN_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) \
+       $(TELE_FAKE_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) \
+       $(TELE_FAKE_SRC) \
+       $(TD_MAIN_SRC)
+
+SRC = \
+       $(ALTOS_SRC) \
+       $(ALTOS_DRIVER_SRC) \
+       $(TELE_DRIVER_SRC) \
+       $(TELE_RECEIVER_SRC) \
+       $(TELE_COMMON_SRC) \
+       $(TELE_FAKE_SRC) \
+       $(TM_DRIVER_SRC) \
+       $(TM_TASK_SRC) \
+       $(TM_MAIN_SRC) \
+       $(TI_MAIN_SRC) \
+       $(TD_MAIN_SRC) \
+       $(TT_MAIN_SRC)
+
+TM_REL=$(TM_SRC:.c=.rel) ao_product-telemetrum.rel
+TI_REL=$(TI_SRC:.c=.rel) ao_product-tidongle.rel
+TT_REL=$(TT_SRC:.c=.rel) ao_product-teleterra.rel
+TD_REL=$(TD_SRC:.c=.rel) ao_product-teledongle.rel
+
+PROD_REL=\
+       ao_product-telemetrum.rel \
+       ao_product-tidongle.rel \
+       ao_product-teleterra.rel \
+       ao_product-teledongle.rel
+
+REL=$(SRC:.c=.rel) $(PROD_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)
+
+PROGS= telemetrum.ihx tidongle.ihx \
+       teleterra.ihx teledongle.ihx
+
+HOST_PROGS=ao_flight_test
+
+PCDB=$(PROGS:.ihx=.cdb)
+PLNK=$(PROGS:.ihx=.lnk)
+PMAP=$(PROGS:.ihx=.map)
+PMEM=$(PROGS:.ihx=.mem)
+PAOM=$(PROGS:.ihx=)
+
+%.rel : %.c $(INC)
+       $(CC) -c $(CFLAGS) -o$*.rel $*.c
+
+all: $(PROGS) $(HOST_PROGS)
+
+telemetrum.ihx: $(TM_REL) Makefile
+       $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(TM_REL)
+       sh check-stack ao.h telemetrum.mem
+
+tidongle.ihx: $(TI_REL) Makefile
+       $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(TI_REL)
+       sh check-stack ao.h tidongle.mem
+
+tidongle.ihx: telemetrum.ihx
+
+teleterra.ihx: $(TT_REL) Makefile
+       $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(TT_REL)
+       sh check-stack ao.h teleterra.mem
+
+teleterra.ihx: tidongle.ihx
+
+teledongle.ihx: $(TD_REL) Makefile
+       $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(TD_REL)
+       sh check-stack ao.h teledongle.mem
+
+teledongle.ihx: teleterra.ihx
+
+altitude.h: make-altitude
+       nickle make-altitude > altitude.h
+
+TELEMETRUM_DEFS=ao-telemetrum.h
+TELETERRA_DEFS=ao-teleterra.h
+TELEDONGLE_DEFS=ao-teledongle.h
+TIDONGLE_DEFS=ao-tidongle.h
+
+ALL_DEFS=$(TELEMETRUM_DEFS) $(TELETERRA_DEFS) \
+       $(TELEDONGLE_DEFS) $(TIDONGLE_DEFS)
+ao_product-telemetrum.rel: ao_product.c $(TELEMETRUM_DEFS)
+       $(CC) -c $(CFLAGS) -D PRODUCT_DEFS='\"$(TELEMETRUM_DEFS)\"' -o$@ ao_product.c
+
+ao_product-teleterra.rel: ao_product.c $(TELETERRA_DEFS)
+       $(CC) -c $(CFLAGS) -D PRODUCT_DEFS='\"$(TELETERRA_DEFS)\"' -o$@ ao_product.c
+
+ao_product-teledongle.rel: ao_product.c $(TELEDONGLE_DEFS)
+       $(CC) -c $(CFLAGS) -D PRODUCT_DEFS='\"$(TELEDONGLE_DEFS)\"' -o$@ ao_product.c
+
+ao_product-tidongle.rel: ao_product.c $(TIDONGLE_DEFS)
+       $(CC) -c $(CFLAGS) -D PRODUCT_DEFS='\"$(TIDONGLE_DEFS)\"' -o$@ ao_product.c
+
+$(TELEMETRUM_DEFS): ao-make-product.5c
+       nickle ao-make-product.5c -m altusmetrum.org -p TeleMetrum -v $(VERSION) > $@
+
+$(TELETERRA_DEFS): ao-make-product.5c
+       nickle ao-make-product.5c -m altusmetrum.org -p TeleTerra -v $(VERSION) > $@
+
+$(TELEDONGLE_DEFS): ao-make-product.5c
+       nickle ao-make-product.5c -m altusmetrum.org -p TeleDongle -v $(VERSION) > $@
+
+$(TIDONGLE_DEFS): ao-make-product.5c
+       nickle ao-make-product.5c -m altusmetrum.org -p TIDongle -v $(VERSION) > $@
+
+clean:
+       rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM)
+       rm -f $(PROGS) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM)
+       rm -f $(ALL_DEFS) $(HOST_PROGS)
+       rm -f $(TELEMETRUM_DEFS) $(TELETERRA_DEFS) $(TELEDONGLE_DEFS) $(TIDONGLE_DEFS)
+
+install:
+
+ao_flight_test: ao_flight.c ao_flight_test.c
+       cc -g -o $@ ao_flight_test.c
diff --git a/src/_bp.c b/src/_bp.c
new file mode 100644 (file)
index 0000000..6bf135b
--- /dev/null
+++ b/src/_bp.c
@@ -0,0 +1,26 @@
+/*-------------------------------------------------------------------------
+
+  _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 ;
diff --git a/src/altitude.h b/src/altitude.h
new file mode 100644 (file)
index 0000000..5225df4
--- /dev/null
@@ -0,0 +1,2048 @@
+       15837,  /*  10.56 kPa 0 count */
+       15804,  /*  10.61 kPa 1 count */
+       15772,  /*  10.66 kPa 2 count */
+       15740,  /*  10.72 kPa 3 count */
+       15708,  /*  10.77 kPa 4 count */
+       15676,  /*  10.83 kPa 5 count */
+       15644,  /*  10.88 kPa 6 count */
+       15613,  /*  10.94 kPa 7 count */
+       15581,  /*  10.99 kPa 8 count */
+       15550,  /*  11.04 kPa 9 count */
+       15519,  /*  11.10 kPa 10 count */
+       15488,  /*  11.15 kPa 11 count */
+       15457,  /*  11.21 kPa 12 count */
+       15426,  /*  11.26 kPa 13 count */
+       15396,  /*  11.32 kPa 14 count */
+       15366,  /*  11.37 kPa 15 count */
+       15335,  /*  11.42 kPa 16 count */
+       15305,  /*  11.48 kPa 17 count */
+       15275,  /*  11.53 kPa 18 count */
+       15246,  /*  11.59 kPa 19 count */
+       15216,  /*  11.64 kPa 20 count */
+       15187,  /*  11.70 kPa 21 count */
+       15157,  /*  11.75 kPa 22 count */
+       15128,  /*  11.80 kPa 23 count */
+       15099,  /*  11.86 kPa 24 count */
+       15070,  /*  11.91 kPa 25 count */
+       15041,  /*  11.97 kPa 26 count */
+       15012,  /*  12.02 kPa 27 count */
+       14984,  /*  12.08 kPa 28 count */
+       14955,  /*  12.13 kPa 29 count */
+       14927,  /*  12.18 kPa 30 count */
+       14899,  /*  12.24 kPa 31 count */
+       14871,  /*  12.29 kPa 32 count */
+       14843,  /*  12.35 kPa 33 count */
+       14815,  /*  12.40 kPa 34 count */
+       14787,  /*  12.46 kPa 35 count */
+       14760,  /*  12.51 kPa 36 count */
+       14732,  /*  12.56 kPa 37 count */
+       14705,  /*  12.62 kPa 38 count */
+       14678,  /*  12.67 kPa 39 count */
+       14651,  /*  12.73 kPa 40 count */
+       14624,  /*  12.78 kPa 41 count */
+       14597,  /*  12.84 kPa 42 count */
+       14570,  /*  12.89 kPa 43 count */
+       14543,  /*  12.94 kPa 44 count */
+       14517,  /*  13.00 kPa 45 count */
+       14490,  /*  13.05 kPa 46 count */
+       14464,  /*  13.11 kPa 47 count */
+       14438,  /*  13.16 kPa 48 count */
+       14412,  /*  13.22 kPa 49 count */
+       14386,  /*  13.27 kPa 50 count */
+       14360,  /*  13.32 kPa 51 count */
+       14334,  /*  13.38 kPa 52 count */
+       14308,  /*  13.43 kPa 53 count */
+       14283,  /*  13.49 kPa 54 count */
+       14257,  /*  13.54 kPa 55 count */
+       14232,  /*  13.60 kPa 56 count */
+       14207,  /*  13.65 kPa 57 count */
+       14182,  /*  13.70 kPa 58 count */
+       14156,  /*  13.76 kPa 59 count */
+       14132,  /*  13.81 kPa 60 count */
+       14107,  /*  13.87 kPa 61 count */
+       14082,  /*  13.92 kPa 62 count */
+       14057,  /*  13.98 kPa 63 count */
+       14033,  /*  14.03 kPa 64 count */
+       14008,  /*  14.08 kPa 65 count */
+       13984,  /*  14.14 kPa 66 count */
+       13959,  /*  14.19 kPa 67 count */
+       13935,  /*  14.25 kPa 68 count */
+       13911,  /*  14.30 kPa 69 count */
+       13887,  /*  14.36 kPa 70 count */
+       13863,  /*  14.41 kPa 71 count */
+       13839,  /*  14.46 kPa 72 count */
+       13816,  /*  14.52 kPa 73 count */
+       13792,  /*  14.57 kPa 74 count */
+       13768,  /*  14.63 kPa 75 count */
+       13745,  /*  14.68 kPa 76 count */
+       13721,  /*  14.74 kPa 77 count */
+       13698,  /*  14.79 kPa 78 count */
+       13675,  /*  14.84 kPa 79 count */
+       13652,  /*  14.90 kPa 80 count */
+       13629,  /*  14.95 kPa 81 count */
+       13606,  /*  15.01 kPa 82 count */
+       13583,  /*  15.06 kPa 83 count */
+       13560,  /*  15.12 kPa 84 count */
+       13537,  /*  15.17 kPa 85 count */
+       13515,  /*  15.22 kPa 86 count */
+       13492,  /*  15.28 kPa 87 count */
+       13470,  /*  15.33 kPa 88 count */
+       13447,  /*  15.39 kPa 89 count */
+       13425,  /*  15.44 kPa 90 count */
+       13403,  /*  15.50 kPa 91 count */
+       13380,  /*  15.55 kPa 92 count */
+       13358,  /*  15.60 kPa 93 count */
+       13336,  /*  15.66 kPa 94 count */
+       13314,  /*  15.71 kPa 95 count */
+       13292,  /*  15.77 kPa 96 count */
+       13271,  /*  15.82 kPa 97 count */
+       13249,  /*  15.87 kPa 98 count */
+       13227,  /*  15.93 kPa 99 count */
+       13206,  /*  15.98 kPa 100 count */
+       13184,  /*  16.04 kPa 101 count */
+       13163,  /*  16.09 kPa 102 count */
+       13141,  /*  16.15 kPa 103 count */
+       13120,  /*  16.20 kPa 104 count */
+       13099,  /*  16.25 kPa 105 count */
+       13078,  /*  16.31 kPa 106 count */
+       13057,  /*  16.36 kPa 107 count */
+       13036,  /*  16.42 kPa 108 count */
+       13015,  /*  16.47 kPa 109 count */
+       12994,  /*  16.53 kPa 110 count */
+       12973,  /*  16.58 kPa 111 count */
+       12952,  /*  16.63 kPa 112 count */
+       12932,  /*  16.69 kPa 113 count */
+       12911,  /*  16.74 kPa 114 count */
+       12891,  /*  16.80 kPa 115 count */
+       12870,  /*  16.85 kPa 116 count */
+       12850,  /*  16.91 kPa 117 count */
+       12829,  /*  16.96 kPa 118 count */
+       12809,  /*  17.01 kPa 119 count */
+       12789,  /*  17.07 kPa 120 count */
+       12769,  /*  17.12 kPa 121 count */
+       12749,  /*  17.18 kPa 122 count */
+       12729,  /*  17.23 kPa 123 count */
+       12709,  /*  17.29 kPa 124 count */
+       12689,  /*  17.34 kPa 125 count */
+       12669,  /*  17.39 kPa 126 count */
+       12649,  /*  17.45 kPa 127 count */
+       12630,  /*  17.50 kPa 128 count */
+       12610,  /*  17.56 kPa 129 count */
+       12590,  /*  17.61 kPa 130 count */
+       12571,  /*  17.67 kPa 131 count */
+       12551,  /*  17.72 kPa 132 count */
+       12532,  /*  17.77 kPa 133 count */
+       12513,  /*  17.83 kPa 134 count */
+       12493,  /*  17.88 kPa 135 count */
+       12474,  /*  17.94 kPa 136 count */
+       12455,  /*  17.99 kPa 137 count */
+       12436,  /*  18.05 kPa 138 count */
+       12417,  /*  18.10 kPa 139 count */
+       12398,  /*  18.15 kPa 140 count */
+       12379,  /*  18.21 kPa 141 count */
+       12360,  /*  18.26 kPa 142 count */
+       12341,  /*  18.32 kPa 143 count */
+       12323,  /*  18.37 kPa 144 count */
+       12304,  /*  18.43 kPa 145 count */
+       12285,  /*  18.48 kPa 146 count */
+       12267,  /*  18.53 kPa 147 count */
+       12248,  /*  18.59 kPa 148 count */
+       12230,  /*  18.64 kPa 149 count */
+       12211,  /*  18.70 kPa 150 count */
+       12193,  /*  18.75 kPa 151 count */
+       12174,  /*  18.81 kPa 152 count */
+       12156,  /*  18.86 kPa 153 count */
+       12138,  /*  18.91 kPa 154 count */
+       12120,  /*  18.97 kPa 155 count */
+       12102,  /*  19.02 kPa 156 count */
+       12084,  /*  19.08 kPa 157 count */
+       12065,  /*  19.13 kPa 158 count */
+       12048,  /*  19.19 kPa 159 count */
+       12030,  /*  19.24 kPa 160 count */
+       12012,  /*  19.29 kPa 161 count */
+       11994,  /*  19.35 kPa 162 count */
+       11976,  /*  19.40 kPa 163 count */
+       11958,  /*  19.46 kPa 164 count */
+       11941,  /*  19.51 kPa 165 count */
+       11923,  /*  19.57 kPa 166 count */
+       11906,  /*  19.62 kPa 167 count */
+       11888,  /*  19.67 kPa 168 count */
+       11871,  /*  19.73 kPa 169 count */
+       11853,  /*  19.78 kPa 170 count */
+       11836,  /*  19.84 kPa 171 count */
+       11818,  /*  19.89 kPa 172 count */
+       11801,  /*  19.95 kPa 173 count */
+       11784,  /*  20.00 kPa 174 count */
+       11767,  /*  20.05 kPa 175 count */
+       11750,  /*  20.11 kPa 176 count */
+       11733,  /*  20.16 kPa 177 count */
+       11715,  /*  20.22 kPa 178 count */
+       11698,  /*  20.27 kPa 179 count */
+       11682,  /*  20.33 kPa 180 count */
+       11665,  /*  20.38 kPa 181 count */
+       11648,  /*  20.43 kPa 182 count */
+       11631,  /*  20.49 kPa 183 count */
+       11614,  /*  20.54 kPa 184 count */
+       11597,  /*  20.60 kPa 185 count */
+       11581,  /*  20.65 kPa 186 count */
+       11564,  /*  20.71 kPa 187 count */
+       11547,  /*  20.76 kPa 188 count */
+       11531,  /*  20.81 kPa 189 count */
+       11514,  /*  20.87 kPa 190 count */
+       11498,  /*  20.92 kPa 191 count */
+       11481,  /*  20.98 kPa 192 count */
+       11465,  /*  21.03 kPa 193 count */
+       11449,  /*  21.09 kPa 194 count */
+       11432,  /*  21.14 kPa 195 count */
+       11416,  /*  21.19 kPa 196 count */
+       11400,  /*  21.25 kPa 197 count */
+       11384,  /*  21.30 kPa 198 count */
+       11368,  /*  21.36 kPa 199 count */
+       11352,  /*  21.41 kPa 200 count */
+       11336,  /*  21.47 kPa 201 count */
+       11319,  /*  21.52 kPa 202 count */
+       11304,  /*  21.57 kPa 203 count */
+       11288,  /*  21.63 kPa 204 count */
+       11272,  /*  21.68 kPa 205 count */
+       11256,  /*  21.74 kPa 206 count */
+       11240,  /*  21.79 kPa 207 count */
+       11224,  /*  21.85 kPa 208 count */
+       11208,  /*  21.90 kPa 209 count */
+       11193,  /*  21.95 kPa 210 count */
+       11177,  /*  22.01 kPa 211 count */
+       11162,  /*  22.06 kPa 212 count */
+       11146,  /*  22.12 kPa 213 count */
+       11130,  /*  22.17 kPa 214 count */
+       11115,  /*  22.23 kPa 215 count */
+       11099,  /*  22.28 kPa 216 count */
+       11084,  /*  22.33 kPa 217 count */
+       11069,  /*  22.39 kPa 218 count */
+       11053,  /*  22.44 kPa 219 count */
+       11038,  /*  22.50 kPa 220 count */
+       11023,  /*  22.55 kPa 221 count */
+       11007,  /*  22.61 kPa 222 count */
+       10992,  /*  22.66 kPa 223 count */
+       10977,  /*  22.71 kPa 224 count */
+       10962,  /*  22.77 kPa 225 count */
+       10947,  /*  22.82 kPa 226 count */
+       10932,  /*  22.88 kPa 227 count */
+       10917,  /*  22.93 kPa 228 count */
+       10902,  /*  22.99 kPa 229 count */
+       10887,  /*  23.04 kPa 230 count */
+       10872,  /*  23.09 kPa 231 count */
+       10857,  /*  23.15 kPa 232 count */
+       10842,  /*  23.20 kPa 233 count */
+       10827,  /*  23.26 kPa 234 count */
+       10812,  /*  23.31 kPa 235 count */
+       10797,  /*  23.37 kPa 236 count */
+       10782,  /*  23.42 kPa 237 count */
+       10768,  /*  23.47 kPa 238 count */
+       10753,  /*  23.53 kPa 239 count */
+       10738,  /*  23.58 kPa 240 count */
+       10723,  /*  23.64 kPa 241 count */
+       10709,  /*  23.69 kPa 242 count */
+       10694,  /*  23.75 kPa 243 count */
+       10679,  /*  23.80 kPa 244 count */
+       10665,  /*  23.85 kPa 245 count */
+       10650,  /*  23.91 kPa 246 count */
+       10636,  /*  23.96 kPa 247 count */
+       10621,  /*  24.02 kPa 248 count */
+       10607,  /*  24.07 kPa 249 count */
+       10592,  /*  24.13 kPa 250 count */
+       10578,  /*  24.18 kPa 251 count */
+       10563,  /*  24.23 kPa 252 count */
+       10549,  /*  24.29 kPa 253 count */
+       10535,  /*  24.34 kPa 254 count */
+       10520,  /*  24.40 kPa 255 count */
+       10506,  /*  24.45 kPa 256 count */
+       10492,  /*  24.51 kPa 257 count */
+       10478,  /*  24.56 kPa 258 count */
+       10463,  /*  24.61 kPa 259 count */
+       10449,  /*  24.67 kPa 260 count */
+       10435,  /*  24.72 kPa 261 count */
+       10421,  /*  24.78 kPa 262 count */
+       10407,  /*  24.83 kPa 263 count */
+       10393,  /*  24.89 kPa 264 count */
+       10379,  /*  24.94 kPa 265 count */
+       10364,  /*  24.99 kPa 266 count */
+       10350,  /*  25.05 kPa 267 count */
+       10336,  /*  25.10 kPa 268 count */
+       10322,  /*  25.16 kPa 269 count */
+       10309,  /*  25.21 kPa 270 count */
+       10295,  /*  25.27 kPa 271 count */
+       10281,  /*  25.32 kPa 272 count */
+       10267,  /*  25.37 kPa 273 count */
+       10253,  /*  25.43 kPa 274 count */
+       10239,  /*  25.48 kPa 275 count */
+       10225,  /*  25.54 kPa 276 count */
+       10212,  /*  25.59 kPa 277 count */
+       10198,  /*  25.65 kPa 278 count */
+       10184,  /*  25.70 kPa 279 count */
+       10170,  /*  25.75 kPa 280 count */
+       10157,  /*  25.81 kPa 281 count */
+       10143,  /*  25.86 kPa 282 count */
+       10129,  /*  25.92 kPa 283 count */
+       10116,  /*  25.97 kPa 284 count */
+       10102,  /*  26.03 kPa 285 count */
+       10089,  /*  26.08 kPa 286 count */
+       10075,  /*  26.13 kPa 287 count */
+       10062,  /*  26.19 kPa 288 count */
+       10048,  /*  26.24 kPa 289 count */
+       10035,  /*  26.30 kPa 290 count */
+       10021,  /*  26.35 kPa 291 count */
+       10008,  /*  26.41 kPa 292 count */
+       9994,   /*  26.46 kPa 293 count */
+       9981,   /*  26.51 kPa 294 count */
+       9967,   /*  26.57 kPa 295 count */
+       9954,   /*  26.62 kPa 296 count */
+       9941,   /*  26.68 kPa 297 count */
+       9928,   /*  26.73 kPa 298 count */
+       9914,   /*  26.79 kPa 299 count */
+       9901,   /*  26.84 kPa 300 count */
+       9888,   /*  26.89 kPa 301 count */
+       9875,   /*  26.95 kPa 302 count */
+       9861,   /*  27.00 kPa 303 count */
+       9848,   /*  27.06 kPa 304 count */
+       9835,   /*  27.11 kPa 305 count */
+       9822,   /*  27.17 kPa 306 count */
+       9809,   /*  27.22 kPa 307 count */
+       9796,   /*  27.27 kPa 308 count */
+       9783,   /*  27.33 kPa 309 count */
+       9770,   /*  27.38 kPa 310 count */
+       9757,   /*  27.44 kPa 311 count */
+       9744,   /*  27.49 kPa 312 count */
+       9731,   /*  27.55 kPa 313 count */
+       9718,   /*  27.60 kPa 314 count */
+       9705,   /*  27.65 kPa 315 count */
+       9692,   /*  27.71 kPa 316 count */
+       9679,   /*  27.76 kPa 317 count */
+       9666,   /*  27.82 kPa 318 count */
+       9653,   /*  27.87 kPa 319 count */
+       9640,   /*  27.93 kPa 320 count */
+       9627,   /*  27.98 kPa 321 count */
+       9615,   /*  28.03 kPa 322 count */
+       9602,   /*  28.09 kPa 323 count */
+       9589,   /*  28.14 kPa 324 count */
+       9576,   /*  28.20 kPa 325 count */
+       9564,   /*  28.25 kPa 326 count */
+       9551,   /*  28.31 kPa 327 count */
+       9538,   /*  28.36 kPa 328 count */
+       9526,   /*  28.41 kPa 329 count */
+       9513,   /*  28.47 kPa 330 count */
+       9500,   /*  28.52 kPa 331 count */
+       9488,   /*  28.58 kPa 332 count */
+       9475,   /*  28.63 kPa 333 count */
+       9463,   /*  28.69 kPa 334 count */
+       9450,   /*  28.74 kPa 335 count */
+       9438,   /*  28.79 kPa 336 count */
+       9425,   /*  28.85 kPa 337 count */
+       9413,   /*  28.90 kPa 338 count */
+       9400,   /*  28.96 kPa 339 count */
+       9388,   /*  29.01 kPa 340 count */
+       9375,   /*  29.07 kPa 341 count */
+       9363,   /*  29.12 kPa 342 count */
+       9350,   /*  29.17 kPa 343 count */
+       9338,   /*  29.23 kPa 344 count */
+       9326,   /*  29.28 kPa 345 count */
+       9313,   /*  29.34 kPa 346 count */
+       9301,   /*  29.39 kPa 347 count */
+       9289,   /*  29.44 kPa 348 count */
+       9276,   /*  29.50 kPa 349 count */
+       9264,   /*  29.55 kPa 350 count */
+       9252,   /*  29.61 kPa 351 count */
+       9240,   /*  29.66 kPa 352 count */
+       9227,   /*  29.72 kPa 353 count */
+       9215,   /*  29.77 kPa 354 count */
+       9203,   /*  29.82 kPa 355 count */
+       9191,   /*  29.88 kPa 356 count */
+       9179,   /*  29.93 kPa 357 count */
+       9167,   /*  29.99 kPa 358 count */
+       9155,   /*  30.04 kPa 359 count */
+       9142,   /*  30.10 kPa 360 count */
+       9130,   /*  30.15 kPa 361 count */
+       9118,   /*  30.20 kPa 362 count */
+       9106,   /*  30.26 kPa 363 count */
+       9094,   /*  30.31 kPa 364 count */
+       9082,   /*  30.37 kPa 365 count */
+       9070,   /*  30.42 kPa 366 count */
+       9058,   /*  30.48 kPa 367 count */
+       9046,   /*  30.53 kPa 368 count */
+       9035,   /*  30.58 kPa 369 count */
+       9023,   /*  30.64 kPa 370 count */
+       9011,   /*  30.69 kPa 371 count */
+       8999,   /*  30.75 kPa 372 count */
+       8987,   /*  30.80 kPa 373 count */
+       8975,   /*  30.86 kPa 374 count */
+       8963,   /*  30.91 kPa 375 count */
+       8952,   /*  30.96 kPa 376 count */
+       8940,   /*  31.02 kPa 377 count */
+       8928,   /*  31.07 kPa 378 count */
+       8916,   /*  31.13 kPa 379 count */
+       8904,   /*  31.18 kPa 380 count */
+       8893,   /*  31.24 kPa 381 count */
+       8881,   /*  31.29 kPa 382 count */
+       8869,   /*  31.34 kPa 383 count */
+       8858,   /*  31.40 kPa 384 count */
+       8846,   /*  31.45 kPa 385 count */
+       8834,   /*  31.51 kPa 386 count */
+       8823,   /*  31.56 kPa 387 count */
+       8811,   /*  31.62 kPa 388 count */
+       8800,   /*  31.67 kPa 389 count */
+       8788,   /*  31.72 kPa 390 count */
+       8776,   /*  31.78 kPa 391 count */
+       8765,   /*  31.83 kPa 392 count */
+       8753,   /*  31.89 kPa 393 count */
+       8742,   /*  31.94 kPa 394 count */
+       8730,   /*  32.00 kPa 395 count */
+       8719,   /*  32.05 kPa 396 count */
+       8707,   /*  32.10 kPa 397 count */
+       8696,   /*  32.16 kPa 398 count */
+       8684,   /*  32.21 kPa 399 count */
+       8673,   /*  32.27 kPa 400 count */
+       8662,   /*  32.32 kPa 401 count */
+       8650,   /*  32.38 kPa 402 count */
+       8639,   /*  32.43 kPa 403 count */
+       8628,   /*  32.48 kPa 404 count */
+       8616,   /*  32.54 kPa 405 count */
+       8605,   /*  32.59 kPa 406 count */
+       8594,   /*  32.65 kPa 407 count */
+       8582,   /*  32.70 kPa 408 count */
+       8571,   /*  32.76 kPa 409 count */
+       8560,   /*  32.81 kPa 410 count */
+       8548,   /*  32.86 kPa 411 count */
+       8537,   /*  32.92 kPa 412 count */
+       8526,   /*  32.97 kPa 413 count */
+       8515,   /*  33.03 kPa 414 count */
+       8504,   /*  33.08 kPa 415 count */
+       8492,   /*  33.14 kPa 416 count */
+       8481,   /*  33.19 kPa 417 count */
+       8470,   /*  33.24 kPa 418 count */
+       8459,   /*  33.30 kPa 419 count */
+       8448,   /*  33.35 kPa 420 count */
+       8437,   /*  33.41 kPa 421 count */
+       8426,   /*  33.46 kPa 422 count */
+       8415,   /*  33.52 kPa 423 count */
+       8403,   /*  33.57 kPa 424 count */
+       8392,   /*  33.62 kPa 425 count */
+       8381,   /*  33.68 kPa 426 count */
+       8370,   /*  33.73 kPa 427 count */
+       8359,   /*  33.79 kPa 428 count */
+       8348,   /*  33.84 kPa 429 count */
+       8337,   /*  33.90 kPa 430 count */
+       8326,   /*  33.95 kPa 431 count */
+       8316,   /*  34.00 kPa 432 count */
+       8305,   /*  34.06 kPa 433 count */
+       8294,   /*  34.11 kPa 434 count */
+       8283,   /*  34.17 kPa 435 count */
+       8272,   /*  34.22 kPa 436 count */
+       8261,   /*  34.28 kPa 437 count */
+       8250,   /*  34.33 kPa 438 count */
+       8239,   /*  34.38 kPa 439 count */
+       8228,   /*  34.44 kPa 440 count */
+       8218,   /*  34.49 kPa 441 count */
+       8207,   /*  34.55 kPa 442 count */
+       8196,   /*  34.60 kPa 443 count */
+       8185,   /*  34.66 kPa 444 count */
+       8175,   /*  34.71 kPa 445 count */
+       8164,   /*  34.76 kPa 446 count */
+       8153,   /*  34.82 kPa 447 count */
+       8142,   /*  34.87 kPa 448 count */
+       8132,   /*  34.93 kPa 449 count */
+       8121,   /*  34.98 kPa 450 count */
+       8110,   /*  35.04 kPa 451 count */
+       8100,   /*  35.09 kPa 452 count */
+       8089,   /*  35.14 kPa 453 count */
+       8078,   /*  35.20 kPa 454 count */
+       8068,   /*  35.25 kPa 455 count */
+       8057,   /*  35.31 kPa 456 count */
+       8046,   /*  35.36 kPa 457 count */
+       8036,   /*  35.42 kPa 458 count */
+       8025,   /*  35.47 kPa 459 count */
+       8015,   /*  35.52 kPa 460 count */
+       8004,   /*  35.58 kPa 461 count */
+       7994,   /*  35.63 kPa 462 count */
+       7983,   /*  35.69 kPa 463 count */
+       7973,   /*  35.74 kPa 464 count */
+       7962,   /*  35.80 kPa 465 count */
+       7952,   /*  35.85 kPa 466 count */
+       7941,   /*  35.90 kPa 467 count */
+       7931,   /*  35.96 kPa 468 count */
+       7920,   /*  36.01 kPa 469 count */
+       7910,   /*  36.07 kPa 470 count */
+       7899,   /*  36.12 kPa 471 count */
+       7889,   /*  36.18 kPa 472 count */
+       7879,   /*  36.23 kPa 473 count */
+       7868,   /*  36.28 kPa 474 count */
+       7858,   /*  36.34 kPa 475 count */
+       7847,   /*  36.39 kPa 476 count */
+       7837,   /*  36.45 kPa 477 count */
+       7827,   /*  36.50 kPa 478 count */
+       7816,   /*  36.56 kPa 479 count */
+       7806,   /*  36.61 kPa 480 count */
+       7796,   /*  36.66 kPa 481 count */
+       7785,   /*  36.72 kPa 482 count */
+       7775,   /*  36.77 kPa 483 count */
+       7765,   /*  36.83 kPa 484 count */
+       7755,   /*  36.88 kPa 485 count */
+       7744,   /*  36.94 kPa 486 count */
+       7734,   /*  36.99 kPa 487 count */
+       7724,   /*  37.04 kPa 488 count */
+       7714,   /*  37.10 kPa 489 count */
+       7704,   /*  37.15 kPa 490 count */
+       7693,   /*  37.21 kPa 491 count */
+       7683,   /*  37.26 kPa 492 count */
+       7673,   /*  37.32 kPa 493 count */
+       7663,   /*  37.37 kPa 494 count */
+       7653,   /*  37.42 kPa 495 count */
+       7643,   /*  37.48 kPa 496 count */
+       7633,   /*  37.53 kPa 497 count */
+       7623,   /*  37.59 kPa 498 count */
+       7613,   /*  37.64 kPa 499 count */
+       7602,   /*  37.70 kPa 500 count */
+       7592,   /*  37.75 kPa 501 count */
+       7582,   /*  37.80 kPa 502 count */
+       7572,   /*  37.86 kPa 503 count */
+       7562,   /*  37.91 kPa 504 count */
+       7552,   /*  37.97 kPa 505 count */
+       7542,   /*  38.02 kPa 506 count */
+       7532,   /*  38.08 kPa 507 count */
+       7522,   /*  38.13 kPa 508 count */
+       7512,   /*  38.18 kPa 509 count */
+       7502,   /*  38.24 kPa 510 count */
+       7492,   /*  38.29 kPa 511 count */
+       7483,   /*  38.35 kPa 512 count */
+       7473,   /*  38.40 kPa 513 count */
+       7463,   /*  38.46 kPa 514 count */
+       7453,   /*  38.51 kPa 515 count */
+       7443,   /*  38.56 kPa 516 count */
+       7433,   /*  38.62 kPa 517 count */
+       7423,   /*  38.67 kPa 518 count */
+       7413,   /*  38.73 kPa 519 count */
+       7403,   /*  38.78 kPa 520 count */
+       7394,   /*  38.84 kPa 521 count */
+       7384,   /*  38.89 kPa 522 count */
+       7374,   /*  38.94 kPa 523 count */
+       7364,   /*  39.00 kPa 524 count */
+       7354,   /*  39.05 kPa 525 count */
+       7345,   /*  39.11 kPa 526 count */
+       7335,   /*  39.16 kPa 527 count */
+       7325,   /*  39.22 kPa 528 count */
+       7315,   /*  39.27 kPa 529 count */
+       7306,   /*  39.32 kPa 530 count */
+       7296,   /*  39.38 kPa 531 count */
+       7286,   /*  39.43 kPa 532 count */
+       7277,   /*  39.49 kPa 533 count */
+       7267,   /*  39.54 kPa 534 count */
+       7257,   /*  39.60 kPa 535 count */
+       7248,   /*  39.65 kPa 536 count */
+       7238,   /*  39.70 kPa 537 count */
+       7228,   /*  39.76 kPa 538 count */
+       7219,   /*  39.81 kPa 539 count */
+       7209,   /*  39.87 kPa 540 count */
+       7199,   /*  39.92 kPa 541 count */
+       7190,   /*  39.98 kPa 542 count */
+       7180,   /*  40.03 kPa 543 count */
+       7171,   /*  40.08 kPa 544 count */
+       7161,   /*  40.14 kPa 545 count */
+       7152,   /*  40.19 kPa 546 count */
+       7142,   /*  40.25 kPa 547 count */
+       7132,   /*  40.30 kPa 548 count */
+       7123,   /*  40.36 kPa 549 count */
+       7113,   /*  40.41 kPa 550 count */
+       7104,   /*  40.46 kPa 551 count */
+       7094,   /*  40.52 kPa 552 count */
+       7085,   /*  40.57 kPa 553 count */
+       7075,   /*  40.63 kPa 554 count */
+       7066,   /*  40.68 kPa 555 count */
+       7056,   /*  40.74 kPa 556 count */
+       7047,   /*  40.79 kPa 557 count */
+       7038,   /*  40.84 kPa 558 count */
+       7028,   /*  40.90 kPa 559 count */
+       7019,   /*  40.95 kPa 560 count */
+       7009,   /*  41.01 kPa 561 count */
+       7000,   /*  41.06 kPa 562 count */
+       6991,   /*  41.12 kPa 563 count */
+       6981,   /*  41.17 kPa 564 count */
+       6972,   /*  41.22 kPa 565 count */
+       6962,   /*  41.28 kPa 566 count */
+       6953,   /*  41.33 kPa 567 count */
+       6944,   /*  41.39 kPa 568 count */
+       6934,   /*  41.44 kPa 569 count */
+       6925,   /*  41.50 kPa 570 count */
+       6916,   /*  41.55 kPa 571 count */
+       6907,   /*  41.60 kPa 572 count */
+       6897,   /*  41.66 kPa 573 count */
+       6888,   /*  41.71 kPa 574 count */
+       6879,   /*  41.77 kPa 575 count */
+       6869,   /*  41.82 kPa 576 count */
+       6860,   /*  41.88 kPa 577 count */
+       6851,   /*  41.93 kPa 578 count */
+       6842,   /*  41.98 kPa 579 count */
+       6833,   /*  42.04 kPa 580 count */
+       6823,   /*  42.09 kPa 581 count */
+       6814,   /*  42.15 kPa 582 count */
+       6805,   /*  42.20 kPa 583 count */
+       6796,   /*  42.26 kPa 584 count */
+       6787,   /*  42.31 kPa 585 count */
+       6777,   /*  42.36 kPa 586 count */
+       6768,   /*  42.42 kPa 587 count */
+       6759,   /*  42.47 kPa 588 count */
+       6750,   /*  42.53 kPa 589 count */
+       6741,   /*  42.58 kPa 590 count */
+       6732,   /*  42.64 kPa 591 count */
+       6723,   /*  42.69 kPa 592 count */
+       6714,   /*  42.74 kPa 593 count */
+       6705,   /*  42.80 kPa 594 count */
+       6695,   /*  42.85 kPa 595 count */
+       6686,   /*  42.91 kPa 596 count */
+       6677,   /*  42.96 kPa 597 count */
+       6668,   /*  43.01 kPa 598 count */
+       6659,   /*  43.07 kPa 599 count */
+       6650,   /*  43.12 kPa 600 count */
+       6641,   /*  43.18 kPa 601 count */
+       6632,   /*  43.23 kPa 602 count */
+       6623,   /*  43.29 kPa 603 count */
+       6614,   /*  43.34 kPa 604 count */
+       6605,   /*  43.39 kPa 605 count */
+       6596,   /*  43.45 kPa 606 count */
+       6587,   /*  43.50 kPa 607 count */
+       6578,   /*  43.56 kPa 608 count */
+       6569,   /*  43.61 kPa 609 count */
+       6560,   /*  43.67 kPa 610 count */
+       6552,   /*  43.72 kPa 611 count */
+       6543,   /*  43.77 kPa 612 count */
+       6534,   /*  43.83 kPa 613 count */
+       6525,   /*  43.88 kPa 614 count */
+       6516,   /*  43.94 kPa 615 count */
+       6507,   /*  43.99 kPa 616 count */
+       6498,   /*  44.05 kPa 617 count */
+       6489,   /*  44.10 kPa 618 count */
+       6480,   /*  44.15 kPa 619 count */
+       6472,   /*  44.21 kPa 620 count */
+       6463,   /*  44.26 kPa 621 count */
+       6454,   /*  44.32 kPa 622 count */
+       6445,   /*  44.37 kPa 623 count */
+       6436,   /*  44.43 kPa 624 count */
+       6427,   /*  44.48 kPa 625 count */
+       6419,   /*  44.53 kPa 626 count */
+       6410,   /*  44.59 kPa 627 count */
+       6401,   /*  44.64 kPa 628 count */
+       6392,   /*  44.70 kPa 629 count */
+       6384,   /*  44.75 kPa 630 count */
+       6375,   /*  44.81 kPa 631 count */
+       6366,   /*  44.86 kPa 632 count */
+       6357,   /*  44.91 kPa 633 count */
+       6349,   /*  44.97 kPa 634 count */
+       6340,   /*  45.02 kPa 635 count */
+       6331,   /*  45.08 kPa 636 count */
+       6322,   /*  45.13 kPa 637 count */
+       6314,   /*  45.19 kPa 638 count */
+       6305,   /*  45.24 kPa 639 count */
+       6296,   /*  45.29 kPa 640 count */
+       6288,   /*  45.35 kPa 641 count */
+       6279,   /*  45.40 kPa 642 count */
+       6270,   /*  45.46 kPa 643 count */
+       6262,   /*  45.51 kPa 644 count */
+       6253,   /*  45.57 kPa 645 count */
+       6245,   /*  45.62 kPa 646 count */
+       6236,   /*  45.67 kPa 647 count */
+       6227,   /*  45.73 kPa 648 count */
+       6219,   /*  45.78 kPa 649 count */
+       6210,   /*  45.84 kPa 650 count */
+       6202,   /*  45.89 kPa 651 count */
+       6193,   /*  45.95 kPa 652 count */
+       6184,   /*  46.00 kPa 653 count */
+       6176,   /*  46.05 kPa 654 count */
+       6167,   /*  46.11 kPa 655 count */
+       6159,   /*  46.16 kPa 656 count */
+       6150,   /*  46.22 kPa 657 count */
+       6142,   /*  46.27 kPa 658 count */
+       6133,   /*  46.33 kPa 659 count */
+       6125,   /*  46.38 kPa 660 count */
+       6116,   /*  46.43 kPa 661 count */
+       6108,   /*  46.49 kPa 662 count */
+       6099,   /*  46.54 kPa 663 count */
+       6091,   /*  46.60 kPa 664 count */
+       6082,   /*  46.65 kPa 665 count */
+       6074,   /*  46.71 kPa 666 count */
+       6065,   /*  46.76 kPa 667 count */
+       6057,   /*  46.81 kPa 668 count */
+       6048,   /*  46.87 kPa 669 count */
+       6040,   /*  46.92 kPa 670 count */
+       6032,   /*  46.98 kPa 671 count */
+       6023,   /*  47.03 kPa 672 count */
+       6015,   /*  47.09 kPa 673 count */
+       6006,   /*  47.14 kPa 674 count */
+       5998,   /*  47.19 kPa 675 count */
+       5990,   /*  47.25 kPa 676 count */
+       5981,   /*  47.30 kPa 677 count */
+       5973,   /*  47.36 kPa 678 count */
+       5964,   /*  47.41 kPa 679 count */
+       5956,   /*  47.47 kPa 680 count */
+       5948,   /*  47.52 kPa 681 count */
+       5939,   /*  47.57 kPa 682 count */
+       5931,   /*  47.63 kPa 683 count */
+       5923,   /*  47.68 kPa 684 count */
+       5914,   /*  47.74 kPa 685 count */
+       5906,   /*  47.79 kPa 686 count */
+       5898,   /*  47.85 kPa 687 count */
+       5890,   /*  47.90 kPa 688 count */
+       5881,   /*  47.95 kPa 689 count */
+       5873,   /*  48.01 kPa 690 count */
+       5865,   /*  48.06 kPa 691 count */
+       5856,   /*  48.12 kPa 692 count */
+       5848,   /*  48.17 kPa 693 count */
+       5840,   /*  48.23 kPa 694 count */
+       5832,   /*  48.28 kPa 695 count */
+       5823,   /*  48.33 kPa 696 count */
+       5815,   /*  48.39 kPa 697 count */
+       5807,   /*  48.44 kPa 698 count */
+       5799,   /*  48.50 kPa 699 count */
+       5791,   /*  48.55 kPa 700 count */
+       5782,   /*  48.61 kPa 701 count */
+       5774,   /*  48.66 kPa 702 count */
+       5766,   /*  48.71 kPa 703 count */
+       5758,   /*  48.77 kPa 704 count */
+       5750,   /*  48.82 kPa 705 count */
+       5742,   /*  48.88 kPa 706 count */
+       5733,   /*  48.93 kPa 707 count */
+       5725,   /*  48.99 kPa 708 count */
+       5717,   /*  49.04 kPa 709 count */
+       5709,   /*  49.09 kPa 710 count */
+       5701,   /*  49.15 kPa 711 count */
+       5693,   /*  49.20 kPa 712 count */
+       5685,   /*  49.26 kPa 713 count */
+       5677,   /*  49.31 kPa 714 count */
+       5668,   /*  49.37 kPa 715 count */
+       5660,   /*  49.42 kPa 716 count */
+       5652,   /*  49.47 kPa 717 count */
+       5644,   /*  49.53 kPa 718 count */
+       5636,   /*  49.58 kPa 719 count */
+       5628,   /*  49.64 kPa 720 count */
+       5620,   /*  49.69 kPa 721 count */
+       5612,   /*  49.75 kPa 722 count */
+       5604,   /*  49.80 kPa 723 count */
+       5596,   /*  49.85 kPa 724 count */
+       5588,   /*  49.91 kPa 725 count */
+       5580,   /*  49.96 kPa 726 count */
+       5572,   /*  50.02 kPa 727 count */
+       5564,   /*  50.07 kPa 728 count */
+       5556,   /*  50.13 kPa 729 count */
+       5548,   /*  50.18 kPa 730 count */
+       5540,   /*  50.23 kPa 731 count */
+       5532,   /*  50.29 kPa 732 count */
+       5524,   /*  50.34 kPa 733 count */
+       5516,   /*  50.40 kPa 734 count */
+       5508,   /*  50.45 kPa 735 count */
+       5500,   /*  50.51 kPa 736 count */
+       5492,   /*  50.56 kPa 737 count */
+       5484,   /*  50.61 kPa 738 count */
+       5476,   /*  50.67 kPa 739 count */
+       5468,   /*  50.72 kPa 740 count */
+       5461,   /*  50.78 kPa 741 count */
+       5453,   /*  50.83 kPa 742 count */
+       5445,   /*  50.89 kPa 743 count */
+       5437,   /*  50.94 kPa 744 count */
+       5429,   /*  50.99 kPa 745 count */
+       5421,   /*  51.05 kPa 746 count */
+       5413,   /*  51.10 kPa 747 count */
+       5405,   /*  51.16 kPa 748 count */
+       5398,   /*  51.21 kPa 749 count */
+       5390,   /*  51.27 kPa 750 count */
+       5382,   /*  51.32 kPa 751 count */
+       5374,   /*  51.37 kPa 752 count */
+       5366,   /*  51.43 kPa 753 count */
+       5358,   /*  51.48 kPa 754 count */
+       5351,   /*  51.54 kPa 755 count */
+       5343,   /*  51.59 kPa 756 count */
+       5335,   /*  51.65 kPa 757 count */
+       5327,   /*  51.70 kPa 758 count */
+       5319,   /*  51.75 kPa 759 count */
+       5312,   /*  51.81 kPa 760 count */
+       5304,   /*  51.86 kPa 761 count */
+       5296,   /*  51.92 kPa 762 count */
+       5288,   /*  51.97 kPa 763 count */
+       5281,   /*  52.03 kPa 764 count */
+       5273,   /*  52.08 kPa 765 count */
+       5265,   /*  52.13 kPa 766 count */
+       5257,   /*  52.19 kPa 767 count */
+       5250,   /*  52.24 kPa 768 count */
+       5242,   /*  52.30 kPa 769 count */
+       5234,   /*  52.35 kPa 770 count */
+       5226,   /*  52.41 kPa 771 count */
+       5219,   /*  52.46 kPa 772 count */
+       5211,   /*  52.51 kPa 773 count */
+       5203,   /*  52.57 kPa 774 count */
+       5196,   /*  52.62 kPa 775 count */
+       5188,   /*  52.68 kPa 776 count */
+       5180,   /*  52.73 kPa 777 count */
+       5173,   /*  52.79 kPa 778 count */
+       5165,   /*  52.84 kPa 779 count */
+       5157,   /*  52.89 kPa 780 count */
+       5150,   /*  52.95 kPa 781 count */
+       5142,   /*  53.00 kPa 782 count */
+       5134,   /*  53.06 kPa 783 count */
+       5127,   /*  53.11 kPa 784 count */
+       5119,   /*  53.17 kPa 785 count */
+       5112,   /*  53.22 kPa 786 count */
+       5104,   /*  53.27 kPa 787 count */
+       5096,   /*  53.33 kPa 788 count */
+       5089,   /*  53.38 kPa 789 count */
+       5081,   /*  53.44 kPa 790 count */
+       5074,   /*  53.49 kPa 791 count */
+       5066,   /*  53.55 kPa 792 count */
+       5058,   /*  53.60 kPa 793 count */
+       5051,   /*  53.65 kPa 794 count */
+       5043,   /*  53.71 kPa 795 count */
+       5036,   /*  53.76 kPa 796 count */
+       5028,   /*  53.82 kPa 797 count */
+       5021,   /*  53.87 kPa 798 count */
+       5013,   /*  53.93 kPa 799 count */
+       5006,   /*  53.98 kPa 800 count */
+       4998,   /*  54.03 kPa 801 count */
+       4991,   /*  54.09 kPa 802 count */
+       4983,   /*  54.14 kPa 803 count */
+       4976,   /*  54.20 kPa 804 count */
+       4968,   /*  54.25 kPa 805 count */
+       4961,   /*  54.31 kPa 806 count */
+       4953,   /*  54.36 kPa 807 count */
+       4946,   /*  54.41 kPa 808 count */
+       4938,   /*  54.47 kPa 809 count */
+       4931,   /*  54.52 kPa 810 count */
+       4923,   /*  54.58 kPa 811 count */
+       4916,   /*  54.63 kPa 812 count */
+       4908,   /*  54.69 kPa 813 count */
+       4901,   /*  54.74 kPa 814 count */
+       4893,   /*  54.79 kPa 815 count */
+       4886,   /*  54.85 kPa 816 count */
+       4879,   /*  54.90 kPa 817 count */
+       4871,   /*  54.96 kPa 818 count */
+       4864,   /*  55.01 kPa 819 count */
+       4856,   /*  55.07 kPa 820 count */
+       4849,   /*  55.12 kPa 821 count */
+       4842,   /*  55.17 kPa 822 count */
+       4834,   /*  55.23 kPa 823 count */
+       4827,   /*  55.28 kPa 824 count */
+       4819,   /*  55.34 kPa 825 count */
+       4812,   /*  55.39 kPa 826 count */
+       4805,   /*  55.45 kPa 827 count */
+       4797,   /*  55.50 kPa 828 count */
+       4790,   /*  55.55 kPa 829 count */
+       4783,   /*  55.61 kPa 830 count */
+       4775,   /*  55.66 kPa 831 count */
+       4768,   /*  55.72 kPa 832 count */
+       4761,   /*  55.77 kPa 833 count */
+       4753,   /*  55.83 kPa 834 count */
+       4746,   /*  55.88 kPa 835 count */
+       4739,   /*  55.93 kPa 836 count */
+       4731,   /*  55.99 kPa 837 count */
+       4724,   /*  56.04 kPa 838 count */
+       4717,   /*  56.10 kPa 839 count */
+       4709,   /*  56.15 kPa 840 count */
+       4702,   /*  56.21 kPa 841 count */
+       4695,   /*  56.26 kPa 842 count */
+       4688,   /*  56.31 kPa 843 count */
+       4680,   /*  56.37 kPa 844 count */
+       4673,   /*  56.42 kPa 845 count */
+       4666,   /*  56.48 kPa 846 count */
+       4659,   /*  56.53 kPa 847 count */
+       4651,   /*  56.58 kPa 848 count */
+       4644,   /*  56.64 kPa 849 count */
+       4637,   /*  56.69 kPa 850 count */
+       4630,   /*  56.75 kPa 851 count */
+       4622,   /*  56.80 kPa 852 count */
+       4615,   /*  56.86 kPa 853 count */
+       4608,   /*  56.91 kPa 854 count */
+       4601,   /*  56.96 kPa 855 count */
+       4594,   /*  57.02 kPa 856 count */
+       4586,   /*  57.07 kPa 857 count */
+       4579,   /*  57.13 kPa 858 count */
+       4572,   /*  57.18 kPa 859 count */
+       4565,   /*  57.24 kPa 860 count */
+       4558,   /*  57.29 kPa 861 count */
+       4550,   /*  57.34 kPa 862 count */
+       4543,   /*  57.40 kPa 863 count */
+       4536,   /*  57.45 kPa 864 count */
+       4529,   /*  57.51 kPa 865 count */
+       4522,   /*  57.56 kPa 866 count */
+       4515,   /*  57.62 kPa 867 count */
+       4508,   /*  57.67 kPa 868 count */
+       4500,   /*  57.72 kPa 869 count */
+       4493,   /*  57.78 kPa 870 count */
+       4486,   /*  57.83 kPa 871 count */
+       4479,   /*  57.89 kPa 872 count */
+       4472,   /*  57.94 kPa 873 count */
+       4465,   /*  58.00 kPa 874 count */
+       4458,   /*  58.05 kPa 875 count */
+       4451,   /*  58.10 kPa 876 count */
+       4444,   /*  58.16 kPa 877 count */
+       4437,   /*  58.21 kPa 878 count */
+       4429,   /*  58.27 kPa 879 count */
+       4422,   /*  58.32 kPa 880 count */
+       4415,   /*  58.38 kPa 881 count */
+       4408,   /*  58.43 kPa 882 count */
+       4401,   /*  58.48 kPa 883 count */
+       4394,   /*  58.54 kPa 884 count */
+       4387,   /*  58.59 kPa 885 count */
+       4380,   /*  58.65 kPa 886 count */
+       4373,   /*  58.70 kPa 887 count */
+       4366,   /*  58.76 kPa 888 count */
+       4359,   /*  58.81 kPa 889 count */
+       4352,   /*  58.86 kPa 890 count */
+       4345,   /*  58.92 kPa 891 count */
+       4338,   /*  58.97 kPa 892 count */
+       4331,   /*  59.03 kPa 893 count */
+       4324,   /*  59.08 kPa 894 count */
+       4317,   /*  59.14 kPa 895 count */
+       4310,   /*  59.19 kPa 896 count */
+       4303,   /*  59.24 kPa 897 count */
+       4296,   /*  59.30 kPa 898 count */
+       4289,   /*  59.35 kPa 899 count */
+       4282,   /*  59.41 kPa 900 count */
+       4275,   /*  59.46 kPa 901 count */
+       4268,   /*  59.52 kPa 902 count */
+       4261,   /*  59.57 kPa 903 count */
+       4254,   /*  59.62 kPa 904 count */
+       4247,   /*  59.68 kPa 905 count */
+       4240,   /*  59.73 kPa 906 count */
+       4234,   /*  59.79 kPa 907 count */
+       4227,   /*  59.84 kPa 908 count */
+       4220,   /*  59.90 kPa 909 count */
+       4213,   /*  59.95 kPa 910 count */
+       4206,   /*  60.00 kPa 911 count */
+       4199,   /*  60.06 kPa 912 count */
+       4192,   /*  60.11 kPa 913 count */
+       4185,   /*  60.17 kPa 914 count */
+       4178,   /*  60.22 kPa 915 count */
+       4171,   /*  60.28 kPa 916 count */
+       4164,   /*  60.33 kPa 917 count */
+       4158,   /*  60.38 kPa 918 count */
+       4151,   /*  60.44 kPa 919 count */
+       4144,   /*  60.49 kPa 920 count */
+       4137,   /*  60.55 kPa 921 count */
+       4130,   /*  60.60 kPa 922 count */
+       4123,   /*  60.66 kPa 923 count */
+       4116,   /*  60.71 kPa 924 count */
+       4110,   /*  60.76 kPa 925 count */
+       4103,   /*  60.82 kPa 926 count */
+       4096,   /*  60.87 kPa 927 count */
+       4089,   /*  60.93 kPa 928 count */
+       4082,   /*  60.98 kPa 929 count */
+       4076,   /*  61.04 kPa 930 count */
+       4069,   /*  61.09 kPa 931 count */
+       4062,   /*  61.14 kPa 932 count */
+       4055,   /*  61.20 kPa 933 count */
+       4048,   /*  61.25 kPa 934 count */
+       4042,   /*  61.31 kPa 935 count */
+       4035,   /*  61.36 kPa 936 count */
+       4028,   /*  61.42 kPa 937 count */
+       4021,   /*  61.47 kPa 938 count */
+       4014,   /*  61.52 kPa 939 count */
+       4008,   /*  61.58 kPa 940 count */
+       4001,   /*  61.63 kPa 941 count */
+       3994,   /*  61.69 kPa 942 count */
+       3987,   /*  61.74 kPa 943 count */
+       3981,   /*  61.80 kPa 944 count */
+       3974,   /*  61.85 kPa 945 count */
+       3967,   /*  61.90 kPa 946 count */
+       3960,   /*  61.96 kPa 947 count */
+       3954,   /*  62.01 kPa 948 count */
+       3947,   /*  62.07 kPa 949 count */
+       3940,   /*  62.12 kPa 950 count */
+       3934,   /*  62.18 kPa 951 count */
+       3927,   /*  62.23 kPa 952 count */
+       3920,   /*  62.28 kPa 953 count */
+       3913,   /*  62.34 kPa 954 count */
+       3907,   /*  62.39 kPa 955 count */
+       3900,   /*  62.45 kPa 956 count */
+       3893,   /*  62.50 kPa 957 count */
+       3887,   /*  62.56 kPa 958 count */
+       3880,   /*  62.61 kPa 959 count */
+       3873,   /*  62.66 kPa 960 count */
+       3867,   /*  62.72 kPa 961 count */
+       3860,   /*  62.77 kPa 962 count */
+       3853,   /*  62.83 kPa 963 count */
+       3847,   /*  62.88 kPa 964 count */
+       3840,   /*  62.94 kPa 965 count */
+       3833,   /*  62.99 kPa 966 count */
+       3827,   /*  63.04 kPa 967 count */
+       3820,   /*  63.10 kPa 968 count */
+       3814,   /*  63.15 kPa 969 count */
+       3807,   /*  63.21 kPa 970 count */
+       3800,   /*  63.26 kPa 971 count */
+       3794,   /*  63.32 kPa 972 count */
+       3787,   /*  63.37 kPa 973 count */
+       3780,   /*  63.42 kPa 974 count */
+       3774,   /*  63.48 kPa 975 count */
+       3767,   /*  63.53 kPa 976 count */
+       3761,   /*  63.59 kPa 977 count */
+       3754,   /*  63.64 kPa 978 count */
+       3748,   /*  63.70 kPa 979 count */
+       3741,   /*  63.75 kPa 980 count */
+       3734,   /*  63.80 kPa 981 count */
+       3728,   /*  63.86 kPa 982 count */
+       3721,   /*  63.91 kPa 983 count */
+       3715,   /*  63.97 kPa 984 count */
+       3708,   /*  64.02 kPa 985 count */
+       3702,   /*  64.08 kPa 986 count */
+       3695,   /*  64.13 kPa 987 count */
+       3688,   /*  64.18 kPa 988 count */
+       3682,   /*  64.24 kPa 989 count */
+       3675,   /*  64.29 kPa 990 count */
+       3669,   /*  64.35 kPa 991 count */
+       3662,   /*  64.40 kPa 992 count */
+       3656,   /*  64.46 kPa 993 count */
+       3649,   /*  64.51 kPa 994 count */
+       3643,   /*  64.56 kPa 995 count */
+       3636,   /*  64.62 kPa 996 count */
+       3630,   /*  64.67 kPa 997 count */
+       3623,   /*  64.73 kPa 998 count */
+       3617,   /*  64.78 kPa 999 count */
+       3610,   /*  64.84 kPa 1000 count */
+       3604,   /*  64.89 kPa 1001 count */
+       3597,   /*  64.94 kPa 1002 count */
+       3591,   /*  65.00 kPa 1003 count */
+       3584,   /*  65.05 kPa 1004 count */
+       3578,   /*  65.11 kPa 1005 count */
+       3571,   /*  65.16 kPa 1006 count */
+       3565,   /*  65.22 kPa 1007 count */
+       3559,   /*  65.27 kPa 1008 count */
+       3552,   /*  65.32 kPa 1009 count */
+       3546,   /*  65.38 kPa 1010 count */
+       3539,   /*  65.43 kPa 1011 count */
+       3533,   /*  65.49 kPa 1012 count */
+       3526,   /*  65.54 kPa 1013 count */
+       3520,   /*  65.60 kPa 1014 count */
+       3514,   /*  65.65 kPa 1015 count */
+       3507,   /*  65.70 kPa 1016 count */
+       3501,   /*  65.76 kPa 1017 count */
+       3494,   /*  65.81 kPa 1018 count */
+       3488,   /*  65.87 kPa 1019 count */
+       3481,   /*  65.92 kPa 1020 count */
+       3475,   /*  65.98 kPa 1021 count */
+       3469,   /*  66.03 kPa 1022 count */
+       3462,   /*  66.08 kPa 1023 count */
+       3456,   /*  66.14 kPa 1024 count */
+       3450,   /*  66.19 kPa 1025 count */
+       3443,   /*  66.25 kPa 1026 count */
+       3437,   /*  66.30 kPa 1027 count */
+       3430,   /*  66.36 kPa 1028 count */
+       3424,   /*  66.41 kPa 1029 count */
+       3418,   /*  66.46 kPa 1030 count */
+       3411,   /*  66.52 kPa 1031 count */
+       3405,   /*  66.57 kPa 1032 count */
+       3399,   /*  66.63 kPa 1033 count */
+       3392,   /*  66.68 kPa 1034 count */
+       3386,   /*  66.74 kPa 1035 count */
+       3380,   /*  66.79 kPa 1036 count */
+       3373,   /*  66.84 kPa 1037 count */
+       3367,   /*  66.90 kPa 1038 count */
+       3361,   /*  66.95 kPa 1039 count */
+       3354,   /*  67.01 kPa 1040 count */
+       3348,   /*  67.06 kPa 1041 count */
+       3342,   /*  67.12 kPa 1042 count */
+       3335,   /*  67.17 kPa 1043 count */
+       3329,   /*  67.22 kPa 1044 count */
+       3323,   /*  67.28 kPa 1045 count */
+       3316,   /*  67.33 kPa 1046 count */
+       3310,   /*  67.39 kPa 1047 count */
+       3304,   /*  67.44 kPa 1048 count */
+       3298,   /*  67.50 kPa 1049 count */
+       3291,   /*  67.55 kPa 1050 count */
+       3285,   /*  67.60 kPa 1051 count */
+       3279,   /*  67.66 kPa 1052 count */
+       3273,   /*  67.71 kPa 1053 count */
+       3266,   /*  67.77 kPa 1054 count */
+       3260,   /*  67.82 kPa 1055 count */
+       3254,   /*  67.88 kPa 1056 count */
+       3248,   /*  67.93 kPa 1057 count */
+       3241,   /*  67.98 kPa 1058 count */
+       3235,   /*  68.04 kPa 1059 count */
+       3229,   /*  68.09 kPa 1060 count */
+       3223,   /*  68.15 kPa 1061 count */
+       3216,   /*  68.20 kPa 1062 count */
+       3210,   /*  68.26 kPa 1063 count */
+       3204,   /*  68.31 kPa 1064 count */
+       3198,   /*  68.36 kPa 1065 count */
+       3191,   /*  68.42 kPa 1066 count */
+       3185,   /*  68.47 kPa 1067 count */
+       3179,   /*  68.53 kPa 1068 count */
+       3173,   /*  68.58 kPa 1069 count */
+       3167,   /*  68.64 kPa 1070 count */
+       3160,   /*  68.69 kPa 1071 count */
+       3154,   /*  68.74 kPa 1072 count */
+       3148,   /*  68.80 kPa 1073 count */
+       3142,   /*  68.85 kPa 1074 count */
+       3136,   /*  68.91 kPa 1075 count */
+       3130,   /*  68.96 kPa 1076 count */
+       3123,   /*  69.02 kPa 1077 count */
+       3117,   /*  69.07 kPa 1078 count */
+       3111,   /*  69.12 kPa 1079 count */
+       3105,   /*  69.18 kPa 1080 count */
+       3099,   /*  69.23 kPa 1081 count */
+       3093,   /*  69.29 kPa 1082 count */
+       3087,   /*  69.34 kPa 1083 count */
+       3080,   /*  69.40 kPa 1084 count */
+       3074,   /*  69.45 kPa 1085 count */
+       3068,   /*  69.50 kPa 1086 count */
+       3062,   /*  69.56 kPa 1087 count */
+       3056,   /*  69.61 kPa 1088 count */
+       3050,   /*  69.67 kPa 1089 count */
+       3044,   /*  69.72 kPa 1090 count */
+       3037,   /*  69.78 kPa 1091 count */
+       3031,   /*  69.83 kPa 1092 count */
+       3025,   /*  69.88 kPa 1093 count */
+       3019,   /*  69.94 kPa 1094 count */
+       3013,   /*  69.99 kPa 1095 count */
+       3007,   /*  70.05 kPa 1096 count */
+       3001,   /*  70.10 kPa 1097 count */
+       2995,   /*  70.15 kPa 1098 count */
+       2989,   /*  70.21 kPa 1099 count */
+       2983,   /*  70.26 kPa 1100 count */
+       2977,   /*  70.32 kPa 1101 count */
+       2970,   /*  70.37 kPa 1102 count */
+       2964,   /*  70.43 kPa 1103 count */
+       2958,   /*  70.48 kPa 1104 count */
+       2952,   /*  70.53 kPa 1105 count */
+       2946,   /*  70.59 kPa 1106 count */
+       2940,   /*  70.64 kPa 1107 count */
+       2934,   /*  70.70 kPa 1108 count */
+       2928,   /*  70.75 kPa 1109 count */
+       2922,   /*  70.81 kPa 1110 count */
+       2916,   /*  70.86 kPa 1111 count */
+       2910,   /*  70.91 kPa 1112 count */
+       2904,   /*  70.97 kPa 1113 count */
+       2898,   /*  71.02 kPa 1114 count */
+       2892,   /*  71.08 kPa 1115 count */
+       2886,   /*  71.13 kPa 1116 count */
+       2880,   /*  71.19 kPa 1117 count */
+       2874,   /*  71.24 kPa 1118 count */
+       2868,   /*  71.29 kPa 1119 count */
+       2862,   /*  71.35 kPa 1120 count */
+       2856,   /*  71.40 kPa 1121 count */
+       2850,   /*  71.46 kPa 1122 count */
+       2844,   /*  71.51 kPa 1123 count */
+       2838,   /*  71.57 kPa 1124 count */
+       2832,   /*  71.62 kPa 1125 count */
+       2826,   /*  71.67 kPa 1126 count */
+       2820,   /*  71.73 kPa 1127 count */
+       2814,   /*  71.78 kPa 1128 count */
+       2808,   /*  71.84 kPa 1129 count */
+       2802,   /*  71.89 kPa 1130 count */
+       2796,   /*  71.95 kPa 1131 count */
+       2790,   /*  72.00 kPa 1132 count */
+       2784,   /*  72.05 kPa 1133 count */
+       2778,   /*  72.11 kPa 1134 count */
+       2772,   /*  72.16 kPa 1135 count */
+       2766,   /*  72.22 kPa 1136 count */
+       2760,   /*  72.27 kPa 1137 count */
+       2754,   /*  72.33 kPa 1138 count */
+       2748,   /*  72.38 kPa 1139 count */
+       2743,   /*  72.43 kPa 1140 count */
+       2737,   /*  72.49 kPa 1141 count */
+       2731,   /*  72.54 kPa 1142 count */
+       2725,   /*  72.60 kPa 1143 count */
+       2719,   /*  72.65 kPa 1144 count */
+       2713,   /*  72.71 kPa 1145 count */
+       2707,   /*  72.76 kPa 1146 count */
+       2701,   /*  72.81 kPa 1147 count */
+       2695,   /*  72.87 kPa 1148 count */
+       2689,   /*  72.92 kPa 1149 count */
+       2683,   /*  72.98 kPa 1150 count */
+       2678,   /*  73.03 kPa 1151 count */
+       2672,   /*  73.09 kPa 1152 count */
+       2666,   /*  73.14 kPa 1153 count */
+       2660,   /*  73.19 kPa 1154 count */
+       2654,   /*  73.25 kPa 1155 count */
+       2648,   /*  73.30 kPa 1156 count */
+       2642,   /*  73.36 kPa 1157 count */
+       2636,   /*  73.41 kPa 1158 count */
+       2631,   /*  73.47 kPa 1159 count */
+       2625,   /*  73.52 kPa 1160 count */
+       2619,   /*  73.57 kPa 1161 count */
+       2613,   /*  73.63 kPa 1162 count */
+       2607,   /*  73.68 kPa 1163 count */
+       2601,   /*  73.74 kPa 1164 count */
+       2595,   /*  73.79 kPa 1165 count */
+       2590,   /*  73.85 kPa 1166 count */
+       2584,   /*  73.90 kPa 1167 count */
+       2578,   /*  73.95 kPa 1168 count */
+       2572,   /*  74.01 kPa 1169 count */
+       2566,   /*  74.06 kPa 1170 count */
+       2560,   /*  74.12 kPa 1171 count */
+       2555,   /*  74.17 kPa 1172 count */
+       2549,   /*  74.23 kPa 1173 count */
+       2543,   /*  74.28 kPa 1174 count */
+       2537,   /*  74.33 kPa 1175 count */
+       2531,   /*  74.39 kPa 1176 count */
+       2526,   /*  74.44 kPa 1177 count */
+       2520,   /*  74.50 kPa 1178 count */
+       2514,   /*  74.55 kPa 1179 count */
+       2508,   /*  74.61 kPa 1180 count */
+       2502,   /*  74.66 kPa 1181 count */
+       2497,   /*  74.71 kPa 1182 count */
+       2491,   /*  74.77 kPa 1183 count */
+       2485,   /*  74.82 kPa 1184 count */
+       2479,   /*  74.88 kPa 1185 count */
+       2473,   /*  74.93 kPa 1186 count */
+       2468,   /*  74.99 kPa 1187 count */
+       2462,   /*  75.04 kPa 1188 count */
+       2456,   /*  75.09 kPa 1189 count */
+       2450,   /*  75.15 kPa 1190 count */
+       2445,   /*  75.20 kPa 1191 count */
+       2439,   /*  75.26 kPa 1192 count */
+       2433,   /*  75.31 kPa 1193 count */
+       2427,   /*  75.37 kPa 1194 count */
+       2422,   /*  75.42 kPa 1195 count */
+       2416,   /*  75.47 kPa 1196 count */
+       2410,   /*  75.53 kPa 1197 count */
+       2405,   /*  75.58 kPa 1198 count */
+       2399,   /*  75.64 kPa 1199 count */
+       2393,   /*  75.69 kPa 1200 count */
+       2387,   /*  75.75 kPa 1201 count */
+       2382,   /*  75.80 kPa 1202 count */
+       2376,   /*  75.85 kPa 1203 count */
+       2370,   /*  75.91 kPa 1204 count */
+       2364,   /*  75.96 kPa 1205 count */
+       2359,   /*  76.02 kPa 1206 count */
+       2353,   /*  76.07 kPa 1207 count */
+       2347,   /*  76.13 kPa 1208 count */
+       2342,   /*  76.18 kPa 1209 count */
+       2336,   /*  76.23 kPa 1210 count */
+       2330,   /*  76.29 kPa 1211 count */
+       2325,   /*  76.34 kPa 1212 count */
+       2319,   /*  76.40 kPa 1213 count */
+       2313,   /*  76.45 kPa 1214 count */
+       2308,   /*  76.51 kPa 1215 count */
+       2302,   /*  76.56 kPa 1216 count */
+       2296,   /*  76.61 kPa 1217 count */
+       2291,   /*  76.67 kPa 1218 count */
+       2285,   /*  76.72 kPa 1219 count */
+       2279,   /*  76.78 kPa 1220 count */
+       2274,   /*  76.83 kPa 1221 count */
+       2268,   /*  76.89 kPa 1222 count */
+       2262,   /*  76.94 kPa 1223 count */
+       2257,   /*  76.99 kPa 1224 count */
+       2251,   /*  77.05 kPa 1225 count */
+       2245,   /*  77.10 kPa 1226 count */
+       2240,   /*  77.16 kPa 1227 count */
+       2234,   /*  77.21 kPa 1228 count */
+       2228,   /*  77.27 kPa 1229 count */
+       2223,   /*  77.32 kPa 1230 count */
+       2217,   /*  77.37 kPa 1231 count */
+       2212,   /*  77.43 kPa 1232 count */
+       2206,   /*  77.48 kPa 1233 count */
+       2200,   /*  77.54 kPa 1234 count */
+       2195,   /*  77.59 kPa 1235 count */
+       2189,   /*  77.65 kPa 1236 count */
+       2184,   /*  77.70 kPa 1237 count */
+       2178,   /*  77.75 kPa 1238 count */
+       2172,   /*  77.81 kPa 1239 count */
+       2167,   /*  77.86 kPa 1240 count */
+       2161,   /*  77.92 kPa 1241 count */
+       2156,   /*  77.97 kPa 1242 count */
+       2150,   /*  78.03 kPa 1243 count */
+       2144,   /*  78.08 kPa 1244 count */
+       2139,   /*  78.13 kPa 1245 count */
+       2133,   /*  78.19 kPa 1246 count */
+       2128,   /*  78.24 kPa 1247 count */
+       2122,   /*  78.30 kPa 1248 count */
+       2117,   /*  78.35 kPa 1249 count */
+       2111,   /*  78.41 kPa 1250 count */
+       2105,   /*  78.46 kPa 1251 count */
+       2100,   /*  78.51 kPa 1252 count */
+       2094,   /*  78.57 kPa 1253 count */
+       2089,   /*  78.62 kPa 1254 count */
+       2083,   /*  78.68 kPa 1255 count */
+       2078,   /*  78.73 kPa 1256 count */
+       2072,   /*  78.79 kPa 1257 count */
+       2067,   /*  78.84 kPa 1258 count */
+       2061,   /*  78.89 kPa 1259 count */
+       2056,   /*  78.95 kPa 1260 count */
+       2050,   /*  79.00 kPa 1261 count */
+       2045,   /*  79.06 kPa 1262 count */
+       2039,   /*  79.11 kPa 1263 count */
+       2033,   /*  79.17 kPa 1264 count */
+       2028,   /*  79.22 kPa 1265 count */
+       2022,   /*  79.27 kPa 1266 count */
+       2017,   /*  79.33 kPa 1267 count */
+       2011,   /*  79.38 kPa 1268 count */
+       2006,   /*  79.44 kPa 1269 count */
+       2000,   /*  79.49 kPa 1270 count */
+       1995,   /*  79.55 kPa 1271 count */
+       1989,   /*  79.60 kPa 1272 count */
+       1984,   /*  79.65 kPa 1273 count */
+       1978,   /*  79.71 kPa 1274 count */
+       1973,   /*  79.76 kPa 1275 count */
+       1967,   /*  79.82 kPa 1276 count */
+       1962,   /*  79.87 kPa 1277 count */
+       1957,   /*  79.93 kPa 1278 count */
+       1951,   /*  79.98 kPa 1279 count */
+       1946,   /*  80.03 kPa 1280 count */
+       1940,   /*  80.09 kPa 1281 count */
+       1935,   /*  80.14 kPa 1282 count */
+       1929,   /*  80.20 kPa 1283 count */
+       1924,   /*  80.25 kPa 1284 count */
+       1918,   /*  80.31 kPa 1285 count */
+       1913,   /*  80.36 kPa 1286 count */
+       1907,   /*  80.41 kPa 1287 count */
+       1902,   /*  80.47 kPa 1288 count */
+       1896,   /*  80.52 kPa 1289 count */
+       1891,   /*  80.58 kPa 1290 count */
+       1886,   /*  80.63 kPa 1291 count */
+       1880,   /*  80.69 kPa 1292 count */
+       1875,   /*  80.74 kPa 1293 count */
+       1869,   /*  80.79 kPa 1294 count */
+       1864,   /*  80.85 kPa 1295 count */
+       1858,   /*  80.90 kPa 1296 count */
+       1853,   /*  80.96 kPa 1297 count */
+       1848,   /*  81.01 kPa 1298 count */
+       1842,   /*  81.07 kPa 1299 count */
+       1837,   /*  81.12 kPa 1300 count */
+       1831,   /*  81.17 kPa 1301 count */
+       1826,   /*  81.23 kPa 1302 count */
+       1821,   /*  81.28 kPa 1303 count */
+       1815,   /*  81.34 kPa 1304 count */
+       1810,   /*  81.39 kPa 1305 count */
+       1804,   /*  81.45 kPa 1306 count */
+       1799,   /*  81.50 kPa 1307 count */
+       1794,   /*  81.55 kPa 1308 count */
+       1788,   /*  81.61 kPa 1309 count */
+       1783,   /*  81.66 kPa 1310 count */
+       1777,   /*  81.72 kPa 1311 count */
+       1772,   /*  81.77 kPa 1312 count */
+       1767,   /*  81.83 kPa 1313 count */
+       1761,   /*  81.88 kPa 1314 count */
+       1756,   /*  81.93 kPa 1315 count */
+       1751,   /*  81.99 kPa 1316 count */
+       1745,   /*  82.04 kPa 1317 count */
+       1740,   /*  82.10 kPa 1318 count */
+       1735,   /*  82.15 kPa 1319 count */
+       1729,   /*  82.21 kPa 1320 count */
+       1724,   /*  82.26 kPa 1321 count */
+       1718,   /*  82.31 kPa 1322 count */
+       1713,   /*  82.37 kPa 1323 count */
+       1708,   /*  82.42 kPa 1324 count */
+       1702,   /*  82.48 kPa 1325 count */
+       1697,   /*  82.53 kPa 1326 count */
+       1692,   /*  82.59 kPa 1327 count */
+       1686,   /*  82.64 kPa 1328 count */
+       1681,   /*  82.69 kPa 1329 count */
+       1676,   /*  82.75 kPa 1330 count */
+       1670,   /*  82.80 kPa 1331 count */
+       1665,   /*  82.86 kPa 1332 count */
+       1660,   /*  82.91 kPa 1333 count */
+       1655,   /*  82.97 kPa 1334 count */
+       1649,   /*  83.02 kPa 1335 count */
+       1644,   /*  83.07 kPa 1336 count */
+       1639,   /*  83.13 kPa 1337 count */
+       1633,   /*  83.18 kPa 1338 count */
+       1628,   /*  83.24 kPa 1339 count */
+       1623,   /*  83.29 kPa 1340 count */
+       1617,   /*  83.35 kPa 1341 count */
+       1612,   /*  83.40 kPa 1342 count */
+       1607,   /*  83.45 kPa 1343 count */
+       1602,   /*  83.51 kPa 1344 count */
+       1596,   /*  83.56 kPa 1345 count */
+       1591,   /*  83.62 kPa 1346 count */
+       1586,   /*  83.67 kPa 1347 count */
+       1580,   /*  83.72 kPa 1348 count */
+       1575,   /*  83.78 kPa 1349 count */
+       1570,   /*  83.83 kPa 1350 count */
+       1565,   /*  83.89 kPa 1351 count */
+       1559,   /*  83.94 kPa 1352 count */
+       1554,   /*  84.00 kPa 1353 count */
+       1549,   /*  84.05 kPa 1354 count */
+       1544,   /*  84.10 kPa 1355 count */
+       1538,   /*  84.16 kPa 1356 count */
+       1533,   /*  84.21 kPa 1357 count */
+       1528,   /*  84.27 kPa 1358 count */
+       1523,   /*  84.32 kPa 1359 count */
+       1517,   /*  84.38 kPa 1360 count */
+       1512,   /*  84.43 kPa 1361 count */
+       1507,   /*  84.48 kPa 1362 count */
+       1502,   /*  84.54 kPa 1363 count */
+       1496,   /*  84.59 kPa 1364 count */
+       1491,   /*  84.65 kPa 1365 count */
+       1486,   /*  84.70 kPa 1366 count */
+       1481,   /*  84.76 kPa 1367 count */
+       1475,   /*  84.81 kPa 1368 count */
+       1470,   /*  84.86 kPa 1369 count */
+       1465,   /*  84.92 kPa 1370 count */
+       1460,   /*  84.97 kPa 1371 count */
+       1455,   /*  85.03 kPa 1372 count */
+       1449,   /*  85.08 kPa 1373 count */
+       1444,   /*  85.14 kPa 1374 count */
+       1439,   /*  85.19 kPa 1375 count */
+       1434,   /*  85.24 kPa 1376 count */
+       1429,   /*  85.30 kPa 1377 count */
+       1423,   /*  85.35 kPa 1378 count */
+       1418,   /*  85.41 kPa 1379 count */
+       1413,   /*  85.46 kPa 1380 count */
+       1408,   /*  85.52 kPa 1381 count */
+       1403,   /*  85.57 kPa 1382 count */
+       1398,   /*  85.62 kPa 1383 count */
+       1392,   /*  85.68 kPa 1384 count */
+       1387,   /*  85.73 kPa 1385 count */
+       1382,   /*  85.79 kPa 1386 count */
+       1377,   /*  85.84 kPa 1387 count */
+       1372,   /*  85.90 kPa 1388 count */
+       1366,   /*  85.95 kPa 1389 count */
+       1361,   /*  86.00 kPa 1390 count */
+       1356,   /*  86.06 kPa 1391 count */
+       1351,   /*  86.11 kPa 1392 count */
+       1346,   /*  86.17 kPa 1393 count */
+       1341,   /*  86.22 kPa 1394 count */
+       1336,   /*  86.28 kPa 1395 count */
+       1330,   /*  86.33 kPa 1396 count */
+       1325,   /*  86.38 kPa 1397 count */
+       1320,   /*  86.44 kPa 1398 count */
+       1315,   /*  86.49 kPa 1399 count */
+       1310,   /*  86.55 kPa 1400 count */
+       1305,   /*  86.60 kPa 1401 count */
+       1300,   /*  86.66 kPa 1402 count */
+       1294,   /*  86.71 kPa 1403 count */
+       1289,   /*  86.76 kPa 1404 count */
+       1284,   /*  86.82 kPa 1405 count */
+       1279,   /*  86.87 kPa 1406 count */
+       1274,   /*  86.93 kPa 1407 count */
+       1269,   /*  86.98 kPa 1408 count */
+       1264,   /*  87.04 kPa 1409 count */
+       1259,   /*  87.09 kPa 1410 count */
+       1254,   /*  87.14 kPa 1411 count */
+       1248,   /*  87.20 kPa 1412 count */
+       1243,   /*  87.25 kPa 1413 count */
+       1238,   /*  87.31 kPa 1414 count */
+       1233,   /*  87.36 kPa 1415 count */
+       1228,   /*  87.42 kPa 1416 count */
+       1223,   /*  87.47 kPa 1417 count */
+       1218,   /*  87.52 kPa 1418 count */
+       1213,   /*  87.58 kPa 1419 count */
+       1208,   /*  87.63 kPa 1420 count */
+       1203,   /*  87.69 kPa 1421 count */
+       1198,   /*  87.74 kPa 1422 count */
+       1192,   /*  87.80 kPa 1423 count */
+       1187,   /*  87.85 kPa 1424 count */
+       1182,   /*  87.90 kPa 1425 count */
+       1177,   /*  87.96 kPa 1426 count */
+       1172,   /*  88.01 kPa 1427 count */
+       1167,   /*  88.07 kPa 1428 count */
+       1162,   /*  88.12 kPa 1429 count */
+       1157,   /*  88.18 kPa 1430 count */
+       1152,   /*  88.23 kPa 1431 count */
+       1147,   /*  88.28 kPa 1432 count */
+       1142,   /*  88.34 kPa 1433 count */
+       1137,   /*  88.39 kPa 1434 count */
+       1132,   /*  88.45 kPa 1435 count */
+       1127,   /*  88.50 kPa 1436 count */
+       1122,   /*  88.56 kPa 1437 count */
+       1117,   /*  88.61 kPa 1438 count */
+       1112,   /*  88.66 kPa 1439 count */
+       1107,   /*  88.72 kPa 1440 count */
+       1102,   /*  88.77 kPa 1441 count */
+       1097,   /*  88.83 kPa 1442 count */
+       1091,   /*  88.88 kPa 1443 count */
+       1086,   /*  88.94 kPa 1444 count */
+       1081,   /*  88.99 kPa 1445 count */
+       1076,   /*  89.04 kPa 1446 count */
+       1071,   /*  89.10 kPa 1447 count */
+       1066,   /*  89.15 kPa 1448 count */
+       1061,   /*  89.21 kPa 1449 count */
+       1056,   /*  89.26 kPa 1450 count */
+       1051,   /*  89.32 kPa 1451 count */
+       1046,   /*  89.37 kPa 1452 count */
+       1041,   /*  89.42 kPa 1453 count */
+       1036,   /*  89.48 kPa 1454 count */
+       1031,   /*  89.53 kPa 1455 count */
+       1026,   /*  89.59 kPa 1456 count */
+       1021,   /*  89.64 kPa 1457 count */
+       1016,   /*  89.70 kPa 1458 count */
+       1011,   /*  89.75 kPa 1459 count */
+       1006,   /*  89.80 kPa 1460 count */
+       1001,   /*  89.86 kPa 1461 count */
+       996,    /*  89.91 kPa 1462 count */
+       992,    /*  89.97 kPa 1463 count */
+       987,    /*  90.02 kPa 1464 count */
+       982,    /*  90.08 kPa 1465 count */
+       977,    /*  90.13 kPa 1466 count */
+       972,    /*  90.18 kPa 1467 count */
+       967,    /*  90.24 kPa 1468 count */
+       962,    /*  90.29 kPa 1469 count */
+       957,    /*  90.35 kPa 1470 count */
+       952,    /*  90.40 kPa 1471 count */
+       947,    /*  90.46 kPa 1472 count */
+       942,    /*  90.51 kPa 1473 count */
+       937,    /*  90.56 kPa 1474 count */
+       932,    /*  90.62 kPa 1475 count */
+       927,    /*  90.67 kPa 1476 count */
+       922,    /*  90.73 kPa 1477 count */
+       917,    /*  90.78 kPa 1478 count */
+       912,    /*  90.84 kPa 1479 count */
+       907,    /*  90.89 kPa 1480 count */
+       902,    /*  90.94 kPa 1481 count */
+       897,    /*  91.00 kPa 1482 count */
+       892,    /*  91.05 kPa 1483 count */
+       888,    /*  91.11 kPa 1484 count */
+       883,    /*  91.16 kPa 1485 count */
+       878,    /*  91.22 kPa 1486 count */
+       873,    /*  91.27 kPa 1487 count */
+       868,    /*  91.32 kPa 1488 count */
+       863,    /*  91.38 kPa 1489 count */
+       858,    /*  91.43 kPa 1490 count */
+       853,    /*  91.49 kPa 1491 count */
+       848,    /*  91.54 kPa 1492 count */
+       843,    /*  91.60 kPa 1493 count */
+       838,    /*  91.65 kPa 1494 count */
+       834,    /*  91.70 kPa 1495 count */
+       829,    /*  91.76 kPa 1496 count */
+       824,    /*  91.81 kPa 1497 count */
+       819,    /*  91.87 kPa 1498 count */
+       814,    /*  91.92 kPa 1499 count */
+       809,    /*  91.98 kPa 1500 count */
+       804,    /*  92.03 kPa 1501 count */
+       799,    /*  92.08 kPa 1502 count */
+       794,    /*  92.14 kPa 1503 count */
+       790,    /*  92.19 kPa 1504 count */
+       785,    /*  92.25 kPa 1505 count */
+       780,    /*  92.30 kPa 1506 count */
+       775,    /*  92.36 kPa 1507 count */
+       770,    /*  92.41 kPa 1508 count */
+       765,    /*  92.46 kPa 1509 count */
+       760,    /*  92.52 kPa 1510 count */
+       755,    /*  92.57 kPa 1511 count */
+       751,    /*  92.63 kPa 1512 count */
+       746,    /*  92.68 kPa 1513 count */
+       741,    /*  92.74 kPa 1514 count */
+       736,    /*  92.79 kPa 1515 count */
+       731,    /*  92.84 kPa 1516 count */
+       726,    /*  92.90 kPa 1517 count */
+       721,    /*  92.95 kPa 1518 count */
+       717,    /*  93.01 kPa 1519 count */
+       712,    /*  93.06 kPa 1520 count */
+       707,    /*  93.12 kPa 1521 count */
+       702,    /*  93.17 kPa 1522 count */
+       697,    /*  93.22 kPa 1523 count */
+       692,    /*  93.28 kPa 1524 count */
+       688,    /*  93.33 kPa 1525 count */
+       683,    /*  93.39 kPa 1526 count */
+       678,    /*  93.44 kPa 1527 count */
+       673,    /*  93.50 kPa 1528 count */
+       668,    /*  93.55 kPa 1529 count */
+       664,    /*  93.60 kPa 1530 count */
+       659,    /*  93.66 kPa 1531 count */
+       654,    /*  93.71 kPa 1532 count */
+       649,    /*  93.77 kPa 1533 count */
+       644,    /*  93.82 kPa 1534 count */
+       639,    /*  93.88 kPa 1535 count */
+       635,    /*  93.93 kPa 1536 count */
+       630,    /*  93.98 kPa 1537 count */
+       625,    /*  94.04 kPa 1538 count */
+       620,    /*  94.09 kPa 1539 count */
+       615,    /*  94.15 kPa 1540 count */
+       611,    /*  94.20 kPa 1541 count */
+       606,    /*  94.26 kPa 1542 count */
+       601,    /*  94.31 kPa 1543 count */
+       596,    /*  94.36 kPa 1544 count */
+       591,    /*  94.42 kPa 1545 count */
+       587,    /*  94.47 kPa 1546 count */
+       582,    /*  94.53 kPa 1547 count */
+       577,    /*  94.58 kPa 1548 count */
+       572,    /*  94.64 kPa 1549 count */
+       568,    /*  94.69 kPa 1550 count */
+       563,    /*  94.74 kPa 1551 count */
+       558,    /*  94.80 kPa 1552 count */
+       553,    /*  94.85 kPa 1553 count */
+       549,    /*  94.91 kPa 1554 count */
+       544,    /*  94.96 kPa 1555 count */
+       539,    /*  95.02 kPa 1556 count */
+       534,    /*  95.07 kPa 1557 count */
+       529,    /*  95.12 kPa 1558 count */
+       525,    /*  95.18 kPa 1559 count */
+       520,    /*  95.23 kPa 1560 count */
+       515,    /*  95.29 kPa 1561 count */
+       510,    /*  95.34 kPa 1562 count */
+       506,    /*  95.40 kPa 1563 count */
+       501,    /*  95.45 kPa 1564 count */
+       496,    /*  95.50 kPa 1565 count */
+       492,    /*  95.56 kPa 1566 count */
+       487,    /*  95.61 kPa 1567 count */
+       482,    /*  95.67 kPa 1568 count */
+       477,    /*  95.72 kPa 1569 count */
+       473,    /*  95.78 kPa 1570 count */
+       468,    /*  95.83 kPa 1571 count */
+       463,    /*  95.88 kPa 1572 count */
+       458,    /*  95.94 kPa 1573 count */
+       454,    /*  95.99 kPa 1574 count */
+       449,    /*  96.05 kPa 1575 count */
+       444,    /*  96.10 kPa 1576 count */
+       440,    /*  96.16 kPa 1577 count */
+       435,    /*  96.21 kPa 1578 count */
+       430,    /*  96.26 kPa 1579 count */
+       425,    /*  96.32 kPa 1580 count */
+       421,    /*  96.37 kPa 1581 count */
+       416,    /*  96.43 kPa 1582 count */
+       411,    /*  96.48 kPa 1583 count */
+       407,    /*  96.54 kPa 1584 count */
+       402,    /*  96.59 kPa 1585 count */
+       397,    /*  96.64 kPa 1586 count */
+       392,    /*  96.70 kPa 1587 count */
+       388,    /*  96.75 kPa 1588 count */
+       383,    /*  96.81 kPa 1589 count */
+       378,    /*  96.86 kPa 1590 count */
+       374,    /*  96.91 kPa 1591 count */
+       369,    /*  96.97 kPa 1592 count */
+       364,    /*  97.02 kPa 1593 count */
+       360,    /*  97.08 kPa 1594 count */
+       355,    /*  97.13 kPa 1595 count */
+       350,    /*  97.19 kPa 1596 count */
+       346,    /*  97.24 kPa 1597 count */
+       341,    /*  97.29 kPa 1598 count */
+       336,    /*  97.35 kPa 1599 count */
+       332,    /*  97.40 kPa 1600 count */
+       327,    /*  97.46 kPa 1601 count */
+       322,    /*  97.51 kPa 1602 count */
+       318,    /*  97.57 kPa 1603 count */
+       313,    /*  97.62 kPa 1604 count */
+       308,    /*  97.67 kPa 1605 count */
+       304,    /*  97.73 kPa 1606 count */
+       299,    /*  97.78 kPa 1607 count */
+       294,    /*  97.84 kPa 1608 count */
+       290,    /*  97.89 kPa 1609 count */
+       285,    /*  97.95 kPa 1610 count */
+       280,    /*  98.00 kPa 1611 count */
+       276,    /*  98.05 kPa 1612 count */
+       271,    /*  98.11 kPa 1613 count */
+       267,    /*  98.16 kPa 1614 count */
+       262,    /*  98.22 kPa 1615 count */
+       257,    /*  98.27 kPa 1616 count */
+       253,    /*  98.33 kPa 1617 count */
+       248,    /*  98.38 kPa 1618 count */
+       243,    /*  98.43 kPa 1619 count */
+       239,    /*  98.49 kPa 1620 count */
+       234,    /*  98.54 kPa 1621 count */
+       230,    /*  98.60 kPa 1622 count */
+       225,    /*  98.65 kPa 1623 count */
+       220,    /*  98.71 kPa 1624 count */
+       216,    /*  98.76 kPa 1625 count */
+       211,    /*  98.81 kPa 1626 count */
+       206,    /*  98.87 kPa 1627 count */
+       202,    /*  98.92 kPa 1628 count */
+       197,    /*  98.98 kPa 1629 count */
+       193,    /*  99.03 kPa 1630 count */
+       188,    /*  99.09 kPa 1631 count */
+       183,    /*  99.14 kPa 1632 count */
+       179,    /*  99.19 kPa 1633 count */
+       174,    /*  99.25 kPa 1634 count */
+       170,    /*  99.30 kPa 1635 count */
+       165,    /*  99.36 kPa 1636 count */
+       160,    /*  99.41 kPa 1637 count */
+       156,    /*  99.47 kPa 1638 count */
+       151,    /*  99.52 kPa 1639 count */
+       147,    /*  99.57 kPa 1640 count */
+       142,    /*  99.63 kPa 1641 count */
+       138,    /*  99.68 kPa 1642 count */
+       133,    /*  99.74 kPa 1643 count */
+       128,    /*  99.79 kPa 1644 count */
+       124,    /*  99.85 kPa 1645 count */
+       119,    /*  99.90 kPa 1646 count */
+       115,    /*  99.95 kPa 1647 count */
+       110,    /* 100.01 kPa 1648 count */
+       106,    /* 100.06 kPa 1649 count */
+       101,    /* 100.12 kPa 1650 count */
+       96,     /* 100.17 kPa 1651 count */
+       92,     /* 100.23 kPa 1652 count */
+       87,     /* 100.28 kPa 1653 count */
+       83,     /* 100.33 kPa 1654 count */
+       78,     /* 100.39 kPa 1655 count */
+       74,     /* 100.44 kPa 1656 count */
+       69,     /* 100.50 kPa 1657 count */
+       65,     /* 100.55 kPa 1658 count */
+       60,     /* 100.61 kPa 1659 count */
+       55,     /* 100.66 kPa 1660 count */
+       51,     /* 100.71 kPa 1661 count */
+       46,     /* 100.77 kPa 1662 count */
+       42,     /* 100.82 kPa 1663 count */
+       37,     /* 100.88 kPa 1664 count */
+       33,     /* 100.93 kPa 1665 count */
+       28,     /* 100.99 kPa 1666 count */
+       24,     /* 101.04 kPa 1667 count */
+       19,     /* 101.09 kPa 1668 count */
+       15,     /* 101.15 kPa 1669 count */
+       10,     /* 101.20 kPa 1670 count */
+       6,      /* 101.26 kPa 1671 count */
+       1,      /* 101.31 kPa 1672 count */
+       -3,     /* 101.37 kPa 1673 count */
+       -8,     /* 101.42 kPa 1674 count */
+       -12,    /* 101.47 kPa 1675 count */
+       -17,    /* 101.53 kPa 1676 count */
+       -21,    /* 101.58 kPa 1677 count */
+       -26,    /* 101.64 kPa 1678 count */
+       -30,    /* 101.69 kPa 1679 count */
+       -35,    /* 101.75 kPa 1680 count */
+       -39,    /* 101.80 kPa 1681 count */
+       -44,    /* 101.85 kPa 1682 count */
+       -48,    /* 101.91 kPa 1683 count */
+       -53,    /* 101.96 kPa 1684 count */
+       -57,    /* 102.02 kPa 1685 count */
+       -62,    /* 102.07 kPa 1686 count */
+       -66,    /* 102.13 kPa 1687 count */
+       -71,    /* 102.18 kPa 1688 count */
+       -75,    /* 102.23 kPa 1689 count */
+       -80,    /* 102.29 kPa 1690 count */
+       -84,    /* 102.34 kPa 1691 count */
+       -89,    /* 102.40 kPa 1692 count */
+       -93,    /* 102.45 kPa 1693 count */
+       -98,    /* 102.51 kPa 1694 count */
+       -102,   /* 102.56 kPa 1695 count */
+       -107,   /* 102.61 kPa 1696 count */
+       -111,   /* 102.67 kPa 1697 count */
+       -116,   /* 102.72 kPa 1698 count */
+       -120,   /* 102.78 kPa 1699 count */
+       -125,   /* 102.83 kPa 1700 count */
+       -129,   /* 102.89 kPa 1701 count */
+       -134,   /* 102.94 kPa 1702 count */
+       -138,   /* 102.99 kPa 1703 count */
+       -143,   /* 103.05 kPa 1704 count */
+       -147,   /* 103.10 kPa 1705 count */
+       -151,   /* 103.16 kPa 1706 count */
+       -156,   /* 103.21 kPa 1707 count */
+       -160,   /* 103.27 kPa 1708 count */
+       -165,   /* 103.32 kPa 1709 count */
+       -169,   /* 103.37 kPa 1710 count */
+       -174,   /* 103.43 kPa 1711 count */
+       -178,   /* 103.48 kPa 1712 count */
+       -183,   /* 103.54 kPa 1713 count */
+       -187,   /* 103.59 kPa 1714 count */
+       -191,   /* 103.65 kPa 1715 count */
+       -196,   /* 103.70 kPa 1716 count */
+       -200,   /* 103.75 kPa 1717 count */
+       -205,   /* 103.81 kPa 1718 count */
+       -209,   /* 103.86 kPa 1719 count */
+       -214,   /* 103.92 kPa 1720 count */
+       -218,   /* 103.97 kPa 1721 count */
+       -222,   /* 104.03 kPa 1722 count */
+       -227,   /* 104.08 kPa 1723 count */
+       -231,   /* 104.13 kPa 1724 count */
+       -236,   /* 104.19 kPa 1725 count */
+       -240,   /* 104.24 kPa 1726 count */
+       -245,   /* 104.30 kPa 1727 count */
+       -249,   /* 104.35 kPa 1728 count */
+       -253,   /* 104.41 kPa 1729 count */
+       -258,   /* 104.46 kPa 1730 count */
+       -262,   /* 104.51 kPa 1731 count */
+       -267,   /* 104.57 kPa 1732 count */
+       -271,   /* 104.62 kPa 1733 count */
+       -275,   /* 104.68 kPa 1734 count */
+       -280,   /* 104.73 kPa 1735 count */
+       -284,   /* 104.79 kPa 1736 count */
+       -289,   /* 104.84 kPa 1737 count */
+       -293,   /* 104.89 kPa 1738 count */
+       -297,   /* 104.95 kPa 1739 count */
+       -302,   /* 105.00 kPa 1740 count */
+       -306,   /* 105.06 kPa 1741 count */
+       -311,   /* 105.11 kPa 1742 count */
+       -315,   /* 105.17 kPa 1743 count */
+       -319,   /* 105.22 kPa 1744 count */
+       -324,   /* 105.27 kPa 1745 count */
+       -328,   /* 105.33 kPa 1746 count */
+       -332,   /* 105.38 kPa 1747 count */
+       -337,   /* 105.44 kPa 1748 count */
+       -341,   /* 105.49 kPa 1749 count */
+       -346,   /* 105.55 kPa 1750 count */
+       -350,   /* 105.60 kPa 1751 count */
+       -354,   /* 105.65 kPa 1752 count */
+       -359,   /* 105.71 kPa 1753 count */
+       -363,   /* 105.76 kPa 1754 count */
+       -367,   /* 105.82 kPa 1755 count */
+       -372,   /* 105.87 kPa 1756 count */
+       -376,   /* 105.93 kPa 1757 count */
+       -380,   /* 105.98 kPa 1758 count */
+       -385,   /* 106.03 kPa 1759 count */
+       -389,   /* 106.09 kPa 1760 count */
+       -394,   /* 106.14 kPa 1761 count */
+       -398,   /* 106.20 kPa 1762 count */
+       -402,   /* 106.25 kPa 1763 count */
+       -407,   /* 106.31 kPa 1764 count */
+       -411,   /* 106.36 kPa 1765 count */
+       -415,   /* 106.41 kPa 1766 count */
+       -420,   /* 106.47 kPa 1767 count */
+       -424,   /* 106.52 kPa 1768 count */
+       -428,   /* 106.58 kPa 1769 count */
+       -433,   /* 106.63 kPa 1770 count */
+       -437,   /* 106.69 kPa 1771 count */
+       -441,   /* 106.74 kPa 1772 count */
+       -446,   /* 106.79 kPa 1773 count */
+       -450,   /* 106.85 kPa 1774 count */
+       -454,   /* 106.90 kPa 1775 count */
+       -459,   /* 106.96 kPa 1776 count */
+       -463,   /* 107.01 kPa 1777 count */
+       -467,   /* 107.07 kPa 1778 count */
+       -472,   /* 107.12 kPa 1779 count */
+       -476,   /* 107.17 kPa 1780 count */
+       -480,   /* 107.23 kPa 1781 count */
+       -485,   /* 107.28 kPa 1782 count */
+       -489,   /* 107.34 kPa 1783 count */
+       -493,   /* 107.39 kPa 1784 count */
+       -497,   /* 107.45 kPa 1785 count */
+       -502,   /* 107.50 kPa 1786 count */
+       -506,   /* 107.55 kPa 1787 count */
+       -510,   /* 107.61 kPa 1788 count */
+       -515,   /* 107.66 kPa 1789 count */
+       -519,   /* 107.72 kPa 1790 count */
+       -523,   /* 107.77 kPa 1791 count */
+       -528,   /* 107.83 kPa 1792 count */
+       -532,   /* 107.88 kPa 1793 count */
+       -536,   /* 107.93 kPa 1794 count */
+       -540,   /* 107.99 kPa 1795 count */
+       -545,   /* 108.04 kPa 1796 count */
+       -549,   /* 108.10 kPa 1797 count */
+       -553,   /* 108.15 kPa 1798 count */
+       -558,   /* 108.21 kPa 1799 count */
+       -562,   /* 108.26 kPa 1800 count */
+       -566,   /* 108.31 kPa 1801 count */
+       -570,   /* 108.37 kPa 1802 count */
+       -575,   /* 108.42 kPa 1803 count */
+       -579,   /* 108.48 kPa 1804 count */
+       -583,   /* 108.53 kPa 1805 count */
+       -588,   /* 108.59 kPa 1806 count */
+       -592,   /* 108.64 kPa 1807 count */
+       -596,   /* 108.69 kPa 1808 count */
+       -600,   /* 108.75 kPa 1809 count */
+       -605,   /* 108.80 kPa 1810 count */
+       -609,   /* 108.86 kPa 1811 count */
+       -613,   /* 108.91 kPa 1812 count */
+       -617,   /* 108.97 kPa 1813 count */
+       -622,   /* 109.02 kPa 1814 count */
+       -626,   /* 109.07 kPa 1815 count */
+       -630,   /* 109.13 kPa 1816 count */
+       -634,   /* 109.18 kPa 1817 count */
+       -639,   /* 109.24 kPa 1818 count */
+       -643,   /* 109.29 kPa 1819 count */
+       -647,   /* 109.35 kPa 1820 count */
+       -651,   /* 109.40 kPa 1821 count */
+       -656,   /* 109.45 kPa 1822 count */
+       -660,   /* 109.51 kPa 1823 count */
+       -664,   /* 109.56 kPa 1824 count */
+       -668,   /* 109.62 kPa 1825 count */
+       -673,   /* 109.67 kPa 1826 count */
+       -677,   /* 109.73 kPa 1827 count */
+       -681,   /* 109.78 kPa 1828 count */
+       -685,   /* 109.83 kPa 1829 count */
+       -690,   /* 109.89 kPa 1830 count */
+       -694,   /* 109.94 kPa 1831 count */
+       -698,   /* 110.00 kPa 1832 count */
+       -702,   /* 110.05 kPa 1833 count */
+       -706,   /* 110.11 kPa 1834 count */
+       -711,   /* 110.16 kPa 1835 count */
+       -715,   /* 110.21 kPa 1836 count */
+       -719,   /* 110.27 kPa 1837 count */
+       -723,   /* 110.32 kPa 1838 count */
+       -728,   /* 110.38 kPa 1839 count */
+       -732,   /* 110.43 kPa 1840 count */
+       -736,   /* 110.48 kPa 1841 count */
+       -740,   /* 110.54 kPa 1842 count */
+       -744,   /* 110.59 kPa 1843 count */
+       -749,   /* 110.65 kPa 1844 count */
+       -753,   /* 110.70 kPa 1845 count */
+       -757,   /* 110.76 kPa 1846 count */
+       -761,   /* 110.81 kPa 1847 count */
+       -765,   /* 110.86 kPa 1848 count */
+       -770,   /* 110.92 kPa 1849 count */
+       -774,   /* 110.97 kPa 1850 count */
+       -778,   /* 111.03 kPa 1851 count */
+       -782,   /* 111.08 kPa 1852 count */
+       -786,   /* 111.14 kPa 1853 count */
+       -791,   /* 111.19 kPa 1854 count */
+       -795,   /* 111.24 kPa 1855 count */
+       -799,   /* 111.30 kPa 1856 count */
+       -803,   /* 111.35 kPa 1857 count */
+       -807,   /* 111.41 kPa 1858 count */
+       -812,   /* 111.46 kPa 1859 count */
+       -816,   /* 111.52 kPa 1860 count */
+       -820,   /* 111.57 kPa 1861 count */
+       -824,   /* 111.62 kPa 1862 count */
+       -828,   /* 111.68 kPa 1863 count */
+       -832,   /* 111.73 kPa 1864 count */
+       -837,   /* 111.79 kPa 1865 count */
+       -841,   /* 111.84 kPa 1866 count */
+       -845,   /* 111.90 kPa 1867 count */
+       -849,   /* 111.95 kPa 1868 count */
+       -853,   /* 112.00 kPa 1869 count */
+       -857,   /* 112.06 kPa 1870 count */
+       -862,   /* 112.11 kPa 1871 count */
+       -866,   /* 112.17 kPa 1872 count */
+       -870,   /* 112.22 kPa 1873 count */
+       -874,   /* 112.28 kPa 1874 count */
+       -878,   /* 112.33 kPa 1875 count */
+       -882,   /* 112.38 kPa 1876 count */
+       -887,   /* 112.44 kPa 1877 count */
+       -891,   /* 112.49 kPa 1878 count */
+       -895,   /* 112.55 kPa 1879 count */
+       -899,   /* 112.60 kPa 1880 count */
+       -903,   /* 112.66 kPa 1881 count */
+       -907,   /* 112.71 kPa 1882 count */
+       -911,   /* 112.76 kPa 1883 count */
+       -916,   /* 112.82 kPa 1884 count */
+       -920,   /* 112.87 kPa 1885 count */
+       -924,   /* 112.93 kPa 1886 count */
+       -928,   /* 112.98 kPa 1887 count */
+       -932,   /* 113.04 kPa 1888 count */
+       -936,   /* 113.09 kPa 1889 count */
+       -940,   /* 113.14 kPa 1890 count */
+       -945,   /* 113.20 kPa 1891 count */
+       -949,   /* 113.25 kPa 1892 count */
+       -953,   /* 113.31 kPa 1893 count */
+       -957,   /* 113.36 kPa 1894 count */
+       -961,   /* 113.42 kPa 1895 count */
+       -965,   /* 113.47 kPa 1896 count */
+       -969,   /* 113.52 kPa 1897 count */
+       -973,   /* 113.58 kPa 1898 count */
+       -978,   /* 113.63 kPa 1899 count */
+       -982,   /* 113.69 kPa 1900 count */
+       -986,   /* 113.74 kPa 1901 count */
+       -990,   /* 113.80 kPa 1902 count */
+       -994,   /* 113.85 kPa 1903 count */
+       -998,   /* 113.90 kPa 1904 count */
+       -1002,  /* 113.96 kPa 1905 count */
+       -1006,  /* 114.01 kPa 1906 count */
+       -1010,  /* 114.07 kPa 1907 count */
+       -1015,  /* 114.12 kPa 1908 count */
+       -1019,  /* 114.18 kPa 1909 count */
+       -1023,  /* 114.23 kPa 1910 count */
+       -1027,  /* 114.28 kPa 1911 count */
+       -1031,  /* 114.34 kPa 1912 count */
+       -1035,  /* 114.39 kPa 1913 count */
+       -1039,  /* 114.45 kPa 1914 count */
+       -1043,  /* 114.50 kPa 1915 count */
+       -1047,  /* 114.56 kPa 1916 count */
+       -1051,  /* 114.61 kPa 1917 count */
+       -1056,  /* 114.66 kPa 1918 count */
+       -1060,  /* 114.72 kPa 1919 count */
+       -1064,  /* 114.77 kPa 1920 count */
+       -1068,  /* 114.83 kPa 1921 count */
+       -1072,  /* 114.88 kPa 1922 count */
+       -1076,  /* 114.94 kPa 1923 count */
+       -1080,  /* 114.99 kPa 1924 count */
+       -1084,  /* 115.04 kPa 1925 count */
+       -1088,  /* 115.10 kPa 1926 count */
+       -1092,  /* 115.15 kPa 1927 count */
+       -1096,  /* 115.21 kPa 1928 count */
+       -1100,  /* 115.26 kPa 1929 count */
+       -1104,  /* 115.32 kPa 1930 count */
+       -1109,  /* 115.37 kPa 1931 count */
+       -1113,  /* 115.42 kPa 1932 count */
+       -1117,  /* 115.48 kPa 1933 count */
+       -1121,  /* 115.53 kPa 1934 count */
+       -1125,  /* 115.59 kPa 1935 count */
+       -1129,  /* 115.64 kPa 1936 count */
+       -1133,  /* 115.70 kPa 1937 count */
+       -1137,  /* 115.75 kPa 1938 count */
+       -1141,  /* 115.80 kPa 1939 count */
+       -1145,  /* 115.86 kPa 1940 count */
+       -1149,  /* 115.91 kPa 1941 count */
+       -1153,  /* 115.97 kPa 1942 count */
+       -1157,  /* 116.02 kPa 1943 count */
+       -1161,  /* 116.08 kPa 1944 count */
+       -1165,  /* 116.13 kPa 1945 count */
+       -1169,  /* 116.18 kPa 1946 count */
+       -1173,  /* 116.24 kPa 1947 count */
+       -1177,  /* 116.29 kPa 1948 count */
+       -1182,  /* 116.35 kPa 1949 count */
+       -1186,  /* 116.40 kPa 1950 count */
+       -1190,  /* 116.46 kPa 1951 count */
+       -1194,  /* 116.51 kPa 1952 count */
+       -1198,  /* 116.56 kPa 1953 count */
+       -1202,  /* 116.62 kPa 1954 count */
+       -1206,  /* 116.67 kPa 1955 count */
+       -1210,  /* 116.73 kPa 1956 count */
+       -1214,  /* 116.78 kPa 1957 count */
+       -1218,  /* 116.84 kPa 1958 count */
+       -1222,  /* 116.89 kPa 1959 count */
+       -1226,  /* 116.94 kPa 1960 count */
+       -1230,  /* 117.00 kPa 1961 count */
+       -1234,  /* 117.05 kPa 1962 count */
+       -1238,  /* 117.11 kPa 1963 count */
+       -1242,  /* 117.16 kPa 1964 count */
+       -1246,  /* 117.22 kPa 1965 count */
+       -1250,  /* 117.27 kPa 1966 count */
+       -1254,  /* 117.32 kPa 1967 count */
+       -1258,  /* 117.38 kPa 1968 count */
+       -1262,  /* 117.43 kPa 1969 count */
+       -1266,  /* 117.49 kPa 1970 count */
+       -1270,  /* 117.54 kPa 1971 count */
+       -1274,  /* 117.60 kPa 1972 count */
+       -1278,  /* 117.65 kPa 1973 count */
+       -1282,  /* 117.70 kPa 1974 count */
+       -1286,  /* 117.76 kPa 1975 count */
+       -1290,  /* 117.81 kPa 1976 count */
+       -1294,  /* 117.87 kPa 1977 count */
+       -1298,  /* 117.92 kPa 1978 count */
+       -1302,  /* 117.98 kPa 1979 count */
+       -1306,  /* 118.03 kPa 1980 count */
+       -1310,  /* 118.08 kPa 1981 count */
+       -1314,  /* 118.14 kPa 1982 count */
+       -1318,  /* 118.19 kPa 1983 count */
+       -1322,  /* 118.25 kPa 1984 count */
+       -1326,  /* 118.30 kPa 1985 count */
+       -1330,  /* 118.36 kPa 1986 count */
+       -1334,  /* 118.41 kPa 1987 count */
+       -1338,  /* 118.46 kPa 1988 count */
+       -1342,  /* 118.52 kPa 1989 count */
+       -1346,  /* 118.57 kPa 1990 count */
+       -1350,  /* 118.63 kPa 1991 count */
+       -1354,  /* 118.68 kPa 1992 count */
+       -1358,  /* 118.74 kPa 1993 count */
+       -1362,  /* 118.79 kPa 1994 count */
+       -1366,  /* 118.84 kPa 1995 count */
+       -1370,  /* 118.90 kPa 1996 count */
+       -1374,  /* 118.95 kPa 1997 count */
+       -1378,  /* 119.01 kPa 1998 count */
+       -1382,  /* 119.06 kPa 1999 count */
+       -1386,  /* 119.12 kPa 2000 count */
+       -1390,  /* 119.17 kPa 2001 count */
+       -1394,  /* 119.22 kPa 2002 count */
+       -1397,  /* 119.28 kPa 2003 count */
+       -1401,  /* 119.33 kPa 2004 count */
+       -1405,  /* 119.39 kPa 2005 count */
+       -1409,  /* 119.44 kPa 2006 count */
+       -1413,  /* 119.50 kPa 2007 count */
+       -1417,  /* 119.55 kPa 2008 count */
+       -1421,  /* 119.60 kPa 2009 count */
+       -1425,  /* 119.66 kPa 2010 count */
+       -1429,  /* 119.71 kPa 2011 count */
+       -1433,  /* 119.77 kPa 2012 count */
+       -1437,  /* 119.82 kPa 2013 count */
+       -1441,  /* 119.88 kPa 2014 count */
+       -1445,  /* 119.93 kPa 2015 count */
+       -1449,  /* 119.98 kPa 2016 count */
+       -1453,  /* 120.04 kPa 2017 count */
+       -1457,  /* 120.09 kPa 2018 count */
+       -1461,  /* 120.15 kPa 2019 count */
+       -1465,  /* 120.20 kPa 2020 count */
+       -1469,  /* 120.26 kPa 2021 count */
+       -1472,  /* 120.31 kPa 2022 count */
+       -1476,  /* 120.36 kPa 2023 count */
+       -1480,  /* 120.42 kPa 2024 count */
+       -1484,  /* 120.47 kPa 2025 count */
+       -1488,  /* 120.53 kPa 2026 count */
+       -1492,  /* 120.58 kPa 2027 count */
+       -1496,  /* 120.64 kPa 2028 count */
+       -1500,  /* 120.69 kPa 2029 count */
+       -1504,  /* 120.74 kPa 2030 count */
+       -1508,  /* 120.80 kPa 2031 count */
+       -1512,  /* 120.85 kPa 2032 count */
+       -1516,  /* 120.91 kPa 2033 count */
+       -1520,  /* 120.96 kPa 2034 count */
+       -1523,  /* 121.02 kPa 2035 count */
+       -1527,  /* 121.07 kPa 2036 count */
+       -1531,  /* 121.12 kPa 2037 count */
+       -1535,  /* 121.18 kPa 2038 count */
+       -1539,  /* 121.23 kPa 2039 count */
+       -1543,  /* 121.29 kPa 2040 count */
+       -1547,  /* 121.34 kPa 2041 count */
+       -1551,  /* 121.40 kPa 2042 count */
+       -1555,  /* 121.45 kPa 2043 count */
+       -1559,  /* 121.50 kPa 2044 count */
+       -1562,  /* 121.56 kPa 2045 count */
+       -1566,  /* 121.61 kPa 2046 count */
+       -1570,  /* 121.67 kPa 2047 count */
diff --git a/src/ao-make-product.5c b/src/ao-make-product.5c
new file mode 100644 (file)
index 0000000..933032d
--- /dev/null
@@ -0,0 +1,88 @@
+#!/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);
+}
+
+string manufacturer = "altusmetrum.org";
+string product = "TeleMetrum";
+string version = "0.0";
+int serial = 1;
+int user_argind = 0;
+
+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 = &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_string(version, "iVersion");
+}
+
+main();
diff --git a/src/ao.h b/src/ao.h
new file mode 100644 (file)
index 0000000..c4cb5bf
--- /dev/null
+++ b/src/ao.h
@@ -0,0 +1,926 @@
+/*
+ * 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 "cc1111.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 0x80
+#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) */
+       uint8_t stack_count;            /* amount of saved stack */
+       uint8_t task_id;                /* index in the task array */
+       __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 */
+void
+ao_sleep(__xdata void *wchan);
+
+/* Wake all tasks sleeping on wchan */
+void
+ao_wakeup(__xdata void *wchan);
+
+/* 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;
+
+/* 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 */
+
+/* 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_MS_TO_TICKS(ms)     ((ms) / 10)
+#define AO_SEC_TO_TICKS(s)     ((s) * 100)
+
+/* 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);
+
+/*
+ * ao_adc.c
+ */
+
+#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 */
+};
+
+/*
+ * 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;
+
+/* 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 */
+#if !AO_NO_ADC_ISR
+void
+ao_adc_isr(void) interrupt 1;
+#endif
+
+/* Initialize the A/D converter */
+void
+ao_adc_init(void);
+
+/*
+ * 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
+#define AO_LED_GREEN   1
+#define AO_LED_RED     2
+
+/* 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);
+
+/* Flush the USB output queue */
+void
+ao_usb_flush(void);
+
+/* USB interrupt handler */
+void
+ao_usb_isr(void) interrupt 6;
+
+/* 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 __xdata uint16_t ao_cmd_lex_i;
+extern __xdata char    ao_cmd_lex_c;
+extern __xdata 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);
+
+struct ao_cmds {
+       char            cmd;
+       void            (*func)(void);
+       const char      *help;
+};
+
+void
+ao_cmd_register(__code struct ao_cmds *cmds);
+
+void
+ao_cmd_init(void);
+
+/*
+ * ao_dma.c
+ */
+
+/* Allocate a DMA channel. the 'done' parameter will be set to 1
+ * 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;
+
+/*
+ * ao_ee.c
+ */
+
+/*
+ * We reserve the last block on the device for
+ * configuration space. Writes and reads in this
+ * area return errors.
+ */
+
+#define AO_EE_BLOCK_SIZE       ((uint16_t) (256))
+#define AO_EE_DEVICE_SIZE      ((uint32_t) 128 * (uint32_t) 1024)
+#define AO_EE_DATA_SIZE                (AO_EE_DEVICE_SIZE - (uint32_t) AO_EE_BLOCK_SIZE)
+#define AO_EE_CONFIG_BLOCK     ((uint16_t) (AO_EE_DATA_SIZE / AO_EE_BLOCK_SIZE))
+
+void
+ao_ee_flush(void) __reentrant;
+
+/* Write to the eeprom */
+uint8_t
+ao_ee_write(uint32_t pos, uint8_t *buf, uint16_t len) __reentrant;
+
+/* Read from the eeprom */
+uint8_t
+ao_ee_read(uint32_t pos, uint8_t *buf, uint16_t len) __reentrant;
+
+/* Write the config block (at the end of the eeprom) */
+uint8_t
+ao_ee_write_config(uint8_t *buf, uint16_t len) __reentrant;
+
+/* Read the config block (at the end of the eeprom) */
+uint8_t
+ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant;
+
+/* Initialize the EEPROM code */
+void
+ao_ee_init(void);
+
+/*
+ * ao_log.c
+ */
+
+/* Structure containing GPS position, either lat or lon */
+
+struct ao_gps_pos {
+       uint8_t degrees;
+       uint8_t minutes;
+       uint16_t minutes_fraction;      /* in units of 1/10000 minutes */
+};
+
+/*
+ * 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_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;
+               struct ao_gps_pos gps_latitude;
+               struct ao_gps_pos gps_longitude;
+               struct {
+                       int16_t         altitude;
+                       uint16_t        unused;
+               } gps_altitude;
+               struct {
+                       uint16_t        d0;
+                       uint16_t        d1;
+               } anon;
+       } u;
+};
+
+/* Write a record to the eeprom log */
+void
+ao_log_data(struct ao_log_record *log);
+
+/* Flush the log */
+void
+ao_log_flush(void);
+
+/* Log dumping API:
+ * ao_log_dump_first() - get first log record
+ * ao_log_dump_next()  - get next log record
+ */
+extern __xdata struct ao_log_record ao_log_dump;
+
+/* Retrieve first log record for the current flight */
+uint8_t
+ao_log_dump_first(void);
+
+/* return next log record for the current flight */
+uint8_t
+ao_log_dump_next(void);
+
+/* Logging thread main routine */
+void
+ao_log(void);
+
+/* 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);
+
+/*
+ * ao_flight.c
+ */
+
+enum ao_flight_state {
+       ao_flight_startup = 0,
+       ao_flight_idle = 1,
+       ao_flight_launchpad = 2,
+       ao_flight_boost = 3,
+       ao_flight_coast = 4,
+       ao_flight_apogee = 5,
+       ao_flight_drogue = 6,
+       ao_flight_main = 7,
+       ao_flight_landed = 8,
+       ao_flight_invalid = 9
+};
+
+extern __xdata struct ao_adc           ao_flight_data;
+extern __pdata enum ao_flight_state    ao_flight_state;
+extern __pdata uint16_t                        ao_flight_tick;
+extern __pdata int16_t                 ao_flight_accel;
+extern __pdata int16_t                 ao_flight_pres;
+extern __pdata int32_t                 ao_flight_vel;
+extern __pdata int16_t                 ao_ground_pres;
+extern __pdata int16_t                 ao_ground_accel;
+extern __pdata int16_t                 ao_min_pres;
+extern __pdata uint16_t                        ao_launch_time;
+
+/* Flight thread */
+void
+ao_flight(void);
+
+/* Initialize flight thread */
+void
+ao_flight_init(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
+ */
+
+#if !AO_NO_SERIAL_ISR
+void
+ao_serial_rx1_isr(void) interrupt 3;
+
+void
+ao_serial_tx1_isr(void) interrupt 14;
+#endif
+
+char
+ao_serial_getchar(void) __critical;
+
+void
+ao_serial_putchar(char c) __critical;
+
+void
+ao_serial_init(void);
+
+/*
+ * 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_LONGITUDE_MASK  (1 << 5)
+#define AO_GPS_LONGITUDE_EAST  (0 << 5)
+#define AO_GPS_LONGITUDE_WEST  (1 << 5)
+
+#define AO_GPS_LATITUDE_MASK   (1 << 6)
+#define AO_GPS_LATITUDE_NORTH  (0 << 6)
+#define AO_GPS_LATITUDE_SOUTH  (1 << 6)
+
+struct ao_gps_data {
+       uint8_t                 hour;
+       uint8_t                 minute;
+       uint8_t                 second;
+       uint8_t                 flags;
+       struct ao_gps_pos       latitude;
+       struct ao_gps_pos       longitude;
+       int16_t                 altitude;
+};
+
+extern __xdata uint8_t ao_gps_mutex;
+extern __xdata struct ao_gps_data ao_gps_data;
+
+void
+ao_gps(void);
+
+void
+ao_gps_print(__xdata struct ao_gps_data *gps_data);
+
+void
+ao_gps_init(void);
+
+/*
+ * ao_gps_report.c
+ */
+
+void
+ao_gps_report(void);
+
+void
+ao_gps_report_init(void);
+
+/*
+ * ao_telemetry.c
+ */
+
+#define AO_MAX_CALLSIGN                8
+
+struct ao_telemetry {
+       uint8_t                 addr;
+       uint8_t                 flight_state;
+       int16_t                 flight_accel;
+       int16_t                 ground_accel;
+       int32_t                 flight_vel;
+       int16_t                 flight_pres;
+       int16_t                 ground_pres;
+       struct ao_adc           adc;
+       struct ao_gps_data      gps;
+       char                    callsign[AO_MAX_CALLSIGN];
+};
+
+/* 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(50)
+#define AO_TELEMETRY_INTERVAL_RECOVER  AO_MS_TO_TICKS(1000)
+
+void
+ao_telemetry_set_interval(uint16_t interval);
+
+void
+ao_telemetry_init(void);
+
+/*
+ * ao_radio.c
+ */
+
+void
+ao_radio_send(__xdata struct ao_telemetry *telemetry) __reentrant;
+
+struct ao_radio_recv {
+       struct ao_telemetry     telemetry;
+       int8_t                  rssi;
+       uint8_t                 status;
+};
+
+void
+ao_radio_recv(__xdata struct ao_radio_recv *recv) __reentrant;
+
+void
+ao_radio_init(void);
+
+/*
+ * ao_monitor.c
+ */
+
+extern const char const * const ao_state_names[];
+
+void
+ao_monitor(void);
+
+void
+ao_set_monitor(uint8_t monitoring);
+
+void
+ao_monitor_init(uint8_t led, uint8_t monitoring) __reentrant;
+
+/*
+ * ao_stdio.c
+ */
+
+void
+flush(void);
+
+/*
+ * 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_igniter_init(void);
+
+/*
+ * ao_config.c
+ */
+
+#define AO_CONFIG_MAJOR        1
+#define AO_CONFIG_MINOR        0
+
+struct ao_config {
+       uint8_t         major;
+       uint8_t         minor;
+       uint16_t        main_deploy;
+       int16_t         accel_zero_g;
+       uint8_t         radio_channel;
+       char            callsign[AO_MAX_CALLSIGN + 1];
+};
+
+extern __xdata struct ao_config ao_config;
+
+void
+ao_config_get(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 uint8_t ao_usb_descriptors [];
+extern const uint16_t ao_serial_number;
+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  32
+#define AO_PACKET_WIN  256
+
+#define AO_PACKET_FIN  (1 << 0)
+#define AO_PACKET_SYN  (1 << 1)
+#define AO_PACKET_RST  (1 << 2)
+#define AO_PACKET_ACK  (1 << 3)
+
+struct ao_packet {
+       uint8_t         addr;
+       uint8_t         flags;
+       uint16_t        seq;
+       uint16_t        ack;
+       uint16_t        window;
+       uint8_t         len;
+       uint8_t         d[AO_PACKET_MAX];
+};
+
+uint8_t
+ao_packet_connect(uint8_t dest);
+
+uint8_t
+ao_packet_accept(void);
+
+int
+ao_packet_send(uint8_t *data, int len);
+
+int
+ao_packet_recv(uint8_t *data, int len);
+
+void
+ao_packet_init(void);
+
+#endif /* _AO_H_ */
diff --git a/src/ao_adc.c b/src/ao_adc.c
new file mode 100644 (file)
index 0000000..26209dc
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * 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;
+
+void
+ao_adc_poll(void)
+{
+       ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 0;
+}
+
+void
+ao_adc_sleep(void)
+{
+       ao_sleep(&ao_adc_ring);
+}
+
+void
+ao_adc_get(__xdata struct ao_adc *packet)
+{
+       uint8_t i = ao_adc_ring_prev(ao_adc_head);
+       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;
+       a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].accel + sequence);
+       a[0] = ADCL;
+       a[1] = ADCH;
+       if (sequence < 5) {
+               /* start next channel conversion */
+               ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | (sequence + 1);
+       } 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(ao_adc_ring);
+       }
+}
+
+static void
+ao_adc_dump(void)
+{
+       __xdata struct ao_adc   packet;
+       ao_adc_get(&packet);
+       printf("tick: %5u accel: %4d pres: %4d temp: %4d batt: %4d drogue: %4d main: %4d\n",
+              packet.tick, packet.accel >> 4, packet.pres >> 4, packet.temp >> 4,
+              packet.v_batt >> 4, packet.sense_d >> 4, packet.sense_m >> 4);
+}
+
+__code struct ao_cmds ao_adc_cmds[] = {
+       { 'a',  ao_adc_dump,    "a                                  Display current ADC values" },
+       { 0,    ao_adc_dump, NULL },
+};
+
+void
+ao_adc_init(void)
+{
+       ADCCFG = ((1 << 0) |    /* acceleration */
+                 (1 << 1) |    /* pressure */
+                 (1 << 2) |    /* temperature */
+                 (1 << 3) |    /* battery voltage */
+                 (1 << 4) |    /* drogue sense */
+                 (1 << 5));    /* main sense */
+
+       /* enable interrupts */
+       ADCIF = 0;
+       IEN0 |= IEN0_ADCIE;
+       ao_cmd_register(&ao_adc_cmds[0]);
+}
diff --git a/src/ao_adc_fake.c b/src/ao_adc_fake.c
new file mode 100644 (file)
index 0000000..6ca88d4
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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)
+{
+}
diff --git a/src/ao_beep.c b/src/ao_beep.c
new file mode 100644 (file)
index 0000000..3642f4c
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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;
+}
diff --git a/src/ao_cmd.c b/src/ao_cmd.c
new file mode 100644 (file)
index 0000000..33619b2
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * 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 uint16_t ao_cmd_lex_i;
+__xdata char   ao_cmd_lex_c;
+__xdata enum ao_cmd_status ao_cmd_status;
+static __xdata uint8_t lex_echo;
+
+#define CMD_LEN        32
+
+static __xdata char    cmd_line[CMD_LEN];
+static __xdata uint8_t cmd_len;
+static __xdata uint8_t cmd_i;
+
+static void
+put_string(char *s)
+{
+       __xdata char    c;
+       while (c = *s++)
+               putchar(c);
+}
+
+static void
+readline(void)
+{
+       __xdata char c;
+       if (lex_echo)
+               put_string("> ");
+       cmd_len = 0;
+       for (;;) {
+               flush();
+               c = getchar();
+               /* backspace/delete */
+               if (c == '\010' || c == '\177') {
+                       if (cmd_len != 0) {
+                               if (lex_echo)
+                                       put_string("\010 \010");
+                               --cmd_len;
+                       }
+                       continue;
+               }
+
+               /* ^U */
+               if (c == '\025') {
+                       while (cmd_len != 0) {
+                               if (lex_echo)
+                                       put_string("\010 \010");
+                               --cmd_len;
+                       }
+                       continue;
+               }
+
+               /* map CR to NL */
+               if (c == '\r')
+                       c = '\n';
+
+               if (c == '\n') {
+                       if (lex_echo)
+                               putchar('\n');
+                       break;
+               }
+
+               if (cmd_len >= CMD_LEN - 2) {
+                       if (lex_echo)
+                               putchar('\007');
+                       continue;
+               }
+               cmd_line[cmd_len++] = c;
+               if (lex_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)
+{
+       int8_t i;
+       for (i = 3; i >= 0; i--)
+               putnibble((v >> (i << 2)) & 0xf);
+}
+
+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)
+{
+       __xdata uint8_t r = ao_cmd_lex_error;
+
+       ao_cmd_lex_i = 0;
+       ao_cmd_white();
+       for(;;) {
+               if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9')
+                       ao_cmd_lex_i = (ao_cmd_lex_i << 4) | (ao_cmd_lex_c - '0');
+               else if ('a' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'f')
+                       ao_cmd_lex_i = (ao_cmd_lex_i << 4) | (ao_cmd_lex_c - 'a' + 10);
+               else if ('A' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'F')
+                       ao_cmd_lex_i = (ao_cmd_lex_i << 4) | (ao_cmd_lex_c - 'A' + 10);
+               else
+                       break;
+               r = ao_cmd_success;
+               ao_cmd_lex();
+       }
+       if (r != ao_cmd_success)
+               ao_cmd_status = r;
+}
+
+void
+ao_cmd_decimal(void)
+{
+       __xdata uint8_t r = ao_cmd_lex_error;
+
+       ao_cmd_lex_i = 0;
+       ao_cmd_white();
+       for(;;) {
+               if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9')
+                       ao_cmd_lex_i = (ao_cmd_lex_i * 10) + (ao_cmd_lex_c - '0');
+               else
+                       break;
+               r = ao_cmd_success;
+               ao_cmd_lex();
+       }
+       if (r != ao_cmd_success)
+               ao_cmd_status = r;
+}
+
+static void
+eol(void)
+{
+       while (ao_cmd_lex_c != '\n')
+               ao_cmd_lex();
+}
+
+static void
+dump(void)
+{
+       __xdata uint16_t c;
+       __xdata uint8_t * __xdata start, * __xdata end;
+
+       ao_cmd_hex();
+       start = (uint8_t __xdata *) ao_cmd_lex_i;
+       ao_cmd_hex();
+       end = (uint8_t __xdata *) ao_cmd_lex_i;
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       c = 0;
+       while (start <= end) {
+               if ((c & 7) == 0) {
+                       if (c)
+                               putchar('\n');
+                       ao_cmd_put16((uint16_t) start);
+               }
+               putchar(' ');
+               ao_cmd_put8(*start);
+               ++c;
+               start++;
+       }
+       putchar('\n');
+}
+
+static void
+echo(void)
+{
+       ao_cmd_hex();
+       lex_echo = ao_cmd_lex_i != 0;
+}
+
+static void
+version(void)
+{
+       printf("manufacturer     %s\n", ao_manufacturer);
+       printf("product          %s\n", ao_product);
+       printf("serial-number    %u\n", ao_serial_number);
+       printf("software-version %s\n", ao_version);
+}
+
+static const char help_txt[] = "All numbers are in hex";
+
+#define NUM_CMDS       11
+
+static __code struct ao_cmds   *__xdata (ao_cmds[NUM_CMDS]);
+static __xdata uint8_t         ao_ncmds;
+
+static void
+help(void)
+{
+       __xdata uint8_t cmds;
+       __xdata uint8_t cmd;
+       __code struct ao_cmds * __xdata cs;
+       puts(help_txt);
+       for (cmds = 0; cmds < ao_ncmds; cmds++) {
+               cs = ao_cmds[cmds];
+               for (cmd = 0; cs[cmd].cmd != '\0'; cmd++)
+                       puts(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 *parameters)
+{
+       __xdata char    c;
+       __xdata uint8_t cmd, cmds;
+       __code struct ao_cmds * __xdata cs;
+       void (*__xdata func)(void);
+       (void) parameters;
+
+       lex_echo = 1;
+       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].cmd != '\0'; cmd++)
+                               if (cs[cmd].cmd == 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,            "?                                  Print this message" },
+       { 'T', ao_task_info,    "T                                  Show task states" },
+       { 'E', echo,            "E <0 off, 1 on>                    Set command echo mode" },
+       { 'd', dump,            "d <start> <end>                    Dump memory" },
+       { 'v', version,         "v                                  Show version" },
+       { 0,    help,   NULL },
+};
+
+void
+ao_cmd_init(void)
+{
+       ao_cmd_register(&ao_base_cmds[0]);
+       ao_add_task(&ao_cmd_task, ao_cmd, "cmd");
+}
diff --git a/src/ao_config.c b/src/ao_config.c
new file mode 100644 (file)
index 0000000..657c7a8
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * 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;
+__xdata uint8_t ao_config_loaded;
+__xdata 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     "KD7SQG"
+#define AO_CONFIG_DEFAULT_ACCEL_ZERO_G 16000
+
+static void
+_ao_config_put(void)
+{
+       ao_ee_write_config((uint8_t *) &ao_config, sizeof (ao_config));
+}
+
+static void
+_ao_config_get(void)
+{
+       if (ao_config_loaded)
+               return;
+       ao_ee_read_config((uint8_t *) &ao_config, sizeof (ao_config));
+       if (ao_config.major != AO_CONFIG_MAJOR) {
+               ao_config.major = AO_CONFIG_MAJOR;
+               ao_config.minor = AO_CONFIG_MINOR;
+               ao_config.main_deploy = AO_CONFIG_DEFAULT_MAIN_DEPLOY;
+               ao_config.radio_channel = AO_CONFIG_DEFAULT_RADIO_CHANNEL;
+               ao_config.accel_zero_g = AO_CONFIG_DEFAULT_ACCEL_ZERO_G;
+               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;
+       }
+       /* deal with minor version issues here, at 0 we haven't any */
+       ao_config_loaded = 1;
+}
+
+void
+ao_config_get(void)
+{
+       ao_mutex_get(&ao_config_mutex);
+       _ao_config_get();
+       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;
+       char callsign[AO_MAX_CALLSIGN + 1];
+
+       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_mutex_get(&ao_config_mutex);
+       _ao_config_get();
+       while (c < AO_MAX_CALLSIGN + 1)
+               callsign[c++] = '\0';
+       memcpy(&ao_config.callsign, &callsign,
+              AO_MAX_CALLSIGN + 1);
+       ao_config_dirty = 1;
+       ao_mutex_put(&ao_config_mutex);
+       ao_config_callsign_show();
+}
+
+void
+ao_config_radio_channel_show(void) __reentrant
+{
+       uint32_t        freq = 434550L + ao_config.radio_channel * 100L;
+       uint16_t        mhz = freq / 1000L;
+       uint16_t        khz = freq % 1000L;
+
+       printf("Radio channel: %d (%d.%03dMHz)\n",
+              ao_config.radio_channel, mhz, khz);
+}
+
+void
+ao_config_radio_channel_set(void) __reentrant
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       ao_mutex_get(&ao_config_mutex);
+       _ao_config_get();
+       ao_config.radio_channel = ao_cmd_lex_i;
+       ao_config_dirty = 1;
+       ao_mutex_put(&ao_config_mutex);
+       ao_config_radio_channel_show();
+}
+
+void
+ao_config_main_deploy_show(void) __reentrant
+{
+       printf("Main deploy set to %d meters (%d feet)\n",
+              ao_config.main_deploy,
+              (int16_t) ((int32_t) ao_config.main_deploy * 328 / 100));
+}
+
+void
+ao_config_main_deploy_set(void) __reentrant
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       ao_mutex_get(&ao_config_mutex);
+       _ao_config_get();
+       ao_config.main_deploy = ao_cmd_lex_i;
+       ao_config_dirty = 1;
+       ao_mutex_put(&ao_config_mutex);
+       ao_config_main_deploy_show();
+}
+
+void
+ao_config_accel_zero_g_show(void) __reentrant
+{
+       printf("Accel zero g point set to %d\n",
+              ao_config.accel_zero_g);
+}
+
+#define ZERO_G_SAMPLES 1000
+
+static int16_t
+ao_config_accel_zero_g_auto(void) __reentrant
+{
+       uint16_t        i;
+       int32_t         accel_total;
+       uint8_t         cal_adc_ring;
+
+       puts("Calibrating accelerometer..."); flush();
+       i = ZERO_G_SAMPLES;
+       accel_total = 0;
+       cal_adc_ring = ao_adc_head;
+       while (i) {
+               ao_sleep(&ao_adc_ring);
+               while (i && cal_adc_ring != ao_adc_head) {
+                       accel_total += (int32_t) ao_adc_ring[cal_adc_ring].accel;
+                       cal_adc_ring = ao_adc_ring_next(cal_adc_ring);
+                       i--;
+               }
+       }
+       return (int16_t) (accel_total / ZERO_G_SAMPLES);
+}
+void
+ao_config_accel_zero_g_set(void) __reentrant
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       if (ao_cmd_lex_i == 0)
+               ao_cmd_lex_i = ao_config_accel_zero_g_auto();
+       ao_mutex_get(&ao_config_mutex);
+       _ao_config_get();
+       ao_config.accel_zero_g = ao_cmd_lex_i;
+       ao_config_dirty = 1;
+       ao_mutex_put(&ao_config_mutex);
+       ao_config_accel_zero_g_show();
+}
+
+struct ao_config_var {
+       char            cmd;
+       void            (*set)(void) __reentrant;
+       void            (*show)(void) __reentrant;
+       const char      *help;
+};
+
+void
+ao_config_help(void) __reentrant;
+
+void
+ao_config_show(void) __reentrant;
+
+void
+ao_config_write(void) __reentrant;
+
+__code struct ao_config_var ao_config_vars[] = {
+       { 'm',  ao_config_main_deploy_set,      ao_config_main_deploy_show,
+               "m <meters>  Set height above launch for main deploy (in meters)" },
+       { 'a',  ao_config_accel_zero_g_set,     ao_config_accel_zero_g_show,
+               "a <value>   Set accelerometer zero g point (0 for auto)" },
+       { 'r',  ao_config_radio_channel_set,    ao_config_radio_channel_show,
+               "r <channel> Set radio channel (freq = 434.550 + channel * .1)" },
+       { 'c',  ao_config_callsign_set,         ao_config_callsign_show,
+               "c <call>    Set callsign broadcast in each packet (8 char max)" },
+       { 's',  ao_config_show,                 ao_config_show,
+               "s           Show current config values" },
+       { 'w',  ao_config_write,                ao_config_write,
+               "w           Write current values to eeprom" },
+       { '?',  ao_config_help,                 ao_config_help,
+               "?           Show available config variables" },
+       { 0,    ao_config_main_deploy_set,      ao_config_main_deploy_show,
+               NULL },
+};
+
+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].cmd != '\0'; cmd++)
+               if (ao_config_vars[cmd].cmd == c) {
+                       func = ao_config_vars[cmd].set;
+                       break;
+               }
+       if (func)
+               (*func)();
+       else
+               ao_cmd_status = ao_cmd_syntax_error;
+}
+
+void
+ao_config_help(void) __reentrant
+{
+       uint8_t cmd;
+       for (cmd = 0; ao_config_vars[cmd].cmd != '\0'; cmd++)
+               puts (ao_config_vars[cmd].help);
+}
+
+void
+ao_config_show(void) __reentrant
+{
+       uint8_t cmd;
+       for (cmd = 0; ao_config_vars[cmd].cmd != '\0'; cmd++)
+               if (ao_config_vars[cmd].show != ao_config_vars[cmd].set)
+                       (*ao_config_vars[cmd].show)();
+}
+
+void
+ao_config_write(void) __reentrant
+{
+       ao_mutex_get(&ao_config_mutex);
+       if (ao_config_dirty) {
+               _ao_config_put();
+               ao_config_dirty = 0;
+               printf("Saved\n");
+       }
+       ao_mutex_put(&ao_config_mutex);
+}
+
+__code struct ao_cmds ao_config_cmds[] = {
+       { 'c',  ao_config_set,  "c <var> <value>                    Set config variable (? for help, s to show)" },
+       { '\0', ao_config_set, NULL },
+};
+
+void
+ao_config_init(void)
+{
+       ao_cmd_register(&ao_config_cmds[0]);
+}
diff --git a/src/ao_convert.c b/src/ao_convert.c
new file mode 100644 (file)
index 0000000..57ed737
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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 const int16_t altitude_table[2048] = {
+#include "altitude.h"
+};
+
+int16_t
+ao_pres_to_altitude(int16_t pres) __reentrant
+{
+       pres = pres >> 4;
+       if (pres < 0) pres = 0;
+       if (pres > 2047) pres = 2047;
+       return altitude_table[pres];
+}
+
+int16_t
+ao_altitude_to_pres(int16_t alt) __reentrant
+{
+       int16_t pres;
+
+       for (pres = 0; pres < 2047; pres++)
+               if (altitude_table[pres] <= alt)
+                       break;
+       return pres << 4;
+}
+
+static __xdata uint8_t ao_temp_mutex;
+
+int16_t
+ao_temp_to_dC(int16_t temp) __reentrant
+{
+       int16_t ret;
+
+       ao_mutex_get(&ao_temp_mutex);
+       ret = (int16_t) ((temp >> 4) * 3300L / 2047L) - 500;
+       ao_mutex_put(&ao_temp_mutex);
+       return ret;
+}
diff --git a/src/ao_dbg.c b/src/ao_dbg.c
new file mode 100644 (file)
index 0000000..c8dc6dd
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * 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 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)
+
+static void
+ao_dbg_send_bits(uint8_t msk, uint8_t val)
+{
+       P0 = (P0 & ~msk) | (val & msk);
+       _asm
+               nop
+               nop
+       _endasm;
+}
+
+void
+ao_dbg_send_byte(uint8_t byte)
+{
+       __xdata uint8_t b, d;
+
+       P0 |= DBG_DATA;
+       P0DIR |= 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);
+       }
+       P0DIR &= ~DBG_DATA;
+}
+
+uint8_t
+ao_dbg_recv_byte(void)
+{
+       __xdata 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
+
+__xdata uint8_t        save_acc;
+__xdata uint8_t save_psw;
+__xdata uint8_t save_dpl0;
+__xdata uint8_t save_dph0;
+__xdata uint8_t save_dpl1;
+__xdata 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)
+{
+       /* Disable peripheral use of P0 */
+       ADCCFG = 0;
+       P0SEL = 0;
+
+
+       /* make P0_4 tri-state */
+       P0INP = DBG_DATA;
+       P2INP &= ~(P2INP_PDUP0_PULL_DOWN);
+
+       /* Raise RESET_N and CLOCK */
+       P0 = DBG_RESET_N | DBG_CLOCK;
+
+       /* RESET_N and CLOCK are outputs now */
+       P0DIR = DBG_RESET_N | DBG_CLOCK;
+}
+
+static void
+ao_dbg_long_delay(void)
+{
+       uint8_t n;
+
+       for (n = 0; n < 20; n++)
+               _asm nop _endasm;
+}
+
+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_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|    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_dbg_long_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_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|    0    );
+       ao_dbg_long_delay();
+       ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
+       ao_dbg_long_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)
+{
+       __xdata uint16_t count;
+       __xdata uint16_t i;
+       __xdata 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)
+{
+       __xdata 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)
+{
+       __xdata uint16_t count;
+       __xdata uint16_t addr;
+       __xdata uint8_t b;
+       __xdata 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)
+{
+       __xdata uint16_t count;
+       __xdata uint16_t addr;
+       __xdata 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] = {
+       { 'D',  debug_enable,   "D                                  Enable debug mode" },
+       { 'G',  debug_get,      "G <count>                          Get data from debug port" },
+       { 'I',  debug_input,    "I <count> <addr>                   Input <count> bytes to target at <addr>" },
+       { 'O',  debug_output,   "O <count> <addr>                   Output <count> bytes to target at <addr>" },
+       { 'P',  debug_put,      "P <byte> ...                       Put data to debug port" },
+       { 'R',  debug_reset,    "R                                  Reset target" },
+       { 0, debug_reset,       0 },
+};
+
+void
+ao_dbg_init(void)
+{
+       ao_cmd_register(&ao_dbg_cmds[0]);
+}
diff --git a/src/ao_dma.c b/src/ao_dma.c
new file mode 100644 (file)
index 0000000..a4d45f1
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * 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;
+       }
+}
diff --git a/src/ao_ee.c b/src/ao_ee.c
new file mode 100644 (file)
index 0000000..f299b92
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * 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"
+
+/*
+ * Using SPI on USART 0, with P1_2 as the chip select
+ */
+
+#define EE_CS          P1_2
+#define EE_CS_INDEX    2
+
+__xdata uint8_t ao_ee_dma_in_done;
+__xdata uint8_t ao_ee_dma_out_done;
+__xdata uint8_t ao_ee_mutex;
+
+uint8_t        ao_ee_dma_out_id;
+uint8_t ao_ee_dma_in_id;
+
+static __xdata uint8_t ao_ee_const = 0xff;
+
+#define ao_ee_delay() do { \
+       _asm nop _endasm; \
+       _asm nop _endasm; \
+       _asm nop _endasm; \
+} while(0)
+
+void ao_ee_cs_low(void)
+{
+       ao_ee_delay();
+       EE_CS = 0;
+       ao_ee_delay();
+}
+
+void ao_ee_cs_high(void)
+{
+       ao_ee_delay();
+       EE_CS = 1;
+       ao_ee_delay();
+}
+
+/* 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
+ */
+static void
+ao_ee_send(void __xdata *block, uint16_t len)
+{
+       ao_dma_set_transfer(ao_ee_dma_in_id,
+                           &U0DBUFXADDR,
+                           &ao_ee_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_ee_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_ee_dma_in_id);
+       ao_dma_start(ao_ee_dma_out_id);
+       ao_dma_trigger(ao_ee_dma_out_id);
+       __critical while (!ao_ee_dma_in_done)
+               ao_sleep(&ao_ee_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.
+ */
+static void
+ao_ee_recv(void __xdata *block, uint16_t len)
+{
+       ao_dma_set_transfer(ao_ee_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_ee_dma_out_id,
+                           &ao_ee_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_ee_dma_in_id);
+       ao_dma_start(ao_ee_dma_out_id);
+       ao_dma_trigger(ao_ee_dma_out_id);
+       __critical while (!ao_ee_dma_in_done)
+               ao_sleep(&ao_ee_dma_in_done);
+}
+
+#define EE_BLOCK       256
+
+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_ee_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_ee_send(&ao_ee_instruction, 1);
+       ao_ee_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_ee_send(&ao_ee_instruction, 2);
+       ao_ee_cs_high();
+}
+
+#define EE_BLOCK_NONE  0xffff
+
+static __xdata uint8_t ao_ee_data[EE_BLOCK];
+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_ee_send(&ao_ee_instruction, 4);
+       ao_ee_send(ao_ee_data, EE_BLOCK);
+       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_ee_send(&ao_ee_instruction, 4);
+       ao_ee_recv(ao_ee_data, EE_BLOCK);
+       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_ee_write(uint32_t pos, uint8_t *buf, uint16_t len) __reentrant
+{
+       uint16_t block;
+       uint16_t this_len;
+       uint8_t this_off;
+
+       if (pos >= AO_EE_DATA_SIZE || pos + len > AO_EE_DATA_SIZE)
+               return 0;
+       while (len) {
+
+               /* Compute portion of transfer within
+                * a single block
+                */
+               this_off = pos;
+               this_len = 256 - (uint16_t) this_off;
+               block = (uint16_t) (pos >> 8);
+               if (this_len > len)
+                       this_len = len;
+               if (this_len & 0xff00)
+                       ao_panic(AO_PANIC_EE);
+
+               /* Transfer the data */
+               ao_mutex_get(&ao_ee_mutex); {
+                       if (this_len != 256)
+                               ao_ee_fill(block);
+                       else {
+                               ao_ee_flush_internal();
+                               ao_ee_block = block;
+                       }
+                       memcpy(ao_ee_data + this_off, buf, this_len);
+                       ao_ee_block_dirty = 1;
+               } ao_mutex_put(&ao_ee_mutex);
+
+               /* See how much is left */
+               buf += this_len;
+               len -= this_len;
+       }
+       return 1;
+}
+
+uint8_t
+ao_ee_read(uint32_t pos, uint8_t *buf, uint16_t len) __reentrant
+{
+       uint16_t block;
+       uint16_t this_len;
+       uint8_t this_off;
+
+       if (pos >= AO_EE_DATA_SIZE || pos + len > AO_EE_DATA_SIZE)
+               return 0;
+       while (len) {
+
+               /* Compute portion of transfer within
+                * a single block
+                */
+               this_off = pos;
+               this_len = 256 - (uint16_t) this_off;
+               block = (uint16_t) (pos >> 8);
+               if (this_len > len)
+                       this_len = len;
+               if (this_len & 0xff00)
+                       ao_panic(AO_PANIC_EE);
+
+               /* Transfer the data */
+               ao_mutex_get(&ao_ee_mutex); {
+                       ao_ee_fill(block);
+                       memcpy(buf, ao_ee_data + this_off, this_len);
+               } ao_mutex_put(&ao_ee_mutex);
+
+               /* See how much is left */
+               buf += this_len;
+               len -= this_len;
+       }
+       return 1;
+}
+
+void
+ao_ee_flush(void) __reentrant
+{
+       ao_mutex_get(&ao_ee_mutex); {
+               ao_ee_flush_internal();
+       } ao_mutex_put(&ao_ee_mutex);
+}
+
+/*
+ * Read/write the config block, which is in
+ * the last block of the ao_eeprom
+ */
+uint8_t
+ao_ee_write_config(uint8_t *buf, uint16_t len) __reentrant
+{
+       if (len > AO_EE_BLOCK_SIZE)
+               return 0;
+       ao_mutex_get(&ao_ee_mutex); {
+               ao_ee_fill(AO_EE_CONFIG_BLOCK);
+               memcpy(ao_ee_data, buf, len);
+               ao_ee_block_dirty = 1;
+               ao_ee_flush_internal();
+       } ao_mutex_put(&ao_ee_mutex);
+       return 1;
+}
+
+uint8_t
+ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant
+{
+       if (len > AO_EE_BLOCK_SIZE)
+               return 0;
+       ao_mutex_get(&ao_ee_mutex); {
+               ao_ee_fill(AO_EE_CONFIG_BLOCK);
+               memcpy(buf, ao_ee_data, len);
+       } ao_mutex_put(&ao_ee_mutex);
+       return 1;
+}
+
+static void
+ee_dump(void)
+{
+       __xdata uint8_t b;
+       __xdata uint16_t block;
+       __xdata uint8_t i;
+
+       ao_cmd_hex();
+       block = ao_cmd_lex_i;
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       i = 0;
+       do {
+               if ((i & 7) == 0) {
+                       if (i)
+                               putchar('\n');
+                       ao_cmd_put16((uint16_t) i);
+               }
+               putchar(' ');
+               ao_ee_read(((uint32_t) block << 8) | i, &b, 1);
+               ao_cmd_put8(b);
+               ++i;
+       } while (i != 0);
+       putchar('\n');
+}
+
+static void
+ee_store(void)
+{
+       __xdata uint16_t block;
+       __xdata uint8_t i;
+       __xdata uint16_t len;
+       __xdata uint8_t b;
+       __xdata 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_ee_write(addr, &b, 1);
+               addr++;
+       }
+       ao_ee_flush();
+}
+
+__code struct ao_cmds ao_ee_cmds[] = {
+       { 'e', ee_dump,         "e <block>                          Dump a block of EEPROM data" },
+       { 'w', ee_store,        "w <block> <start> <len> <data> ... Write data to EEPROM" },
+       { 0,   ee_store, NULL },
+};
+
+/*
+ * To initialize the chip, set up the CS line and
+ * the SPI interface
+ */
+void
+ao_ee_init(void)
+{
+       /* set up CS */
+       EE_CS = 1;
+       P1DIR |= (1 << EE_CS_INDEX);
+       P1SEL &= ~(1 << EE_CS_INDEX);
+
+       /* 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_ee_dma_out_id = ao_dma_alloc(&ao_ee_dma_out_done);
+
+       /* Set up IN DMA */
+       ao_ee_dma_in_id = ao_dma_alloc(&ao_ee_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,
+        * while the 25LC1024 is limited to 20MHz. So,
+        * use the 3MHz clock (BAUD_E 17, BAUD_M 0)
+        */
+       U0BAUD = 0;
+       U0GCR = (UxGCR_CPOL_NEGATIVE |
+                UxGCR_CPHA_FIRST_EDGE |
+                UxGCR_ORDER_MSB |
+                (17 << UxGCR_BAUD_E_SHIFT));
+       ao_cmd_register(&ao_ee_cmds[0]);
+}
diff --git a/src/ao_ee_fake.c b/src/ao_ee_fake.c
new file mode 100644 (file)
index 0000000..b0c1d61
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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;
+}
diff --git a/src/ao_flight.c b/src/ao_flight.c
new file mode 100644 (file)
index 0000000..c0f5683
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+ * 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
+
+/* Main flight thread. */
+
+__pdata enum ao_flight_state   ao_flight_state;        /* current flight state */
+__pdata uint16_t               ao_flight_tick;         /* time of last data */
+__pdata uint16_t               ao_flight_prev_tick;    /* time of previous data */
+__pdata int16_t                        ao_flight_accel;        /* filtered acceleration */
+__pdata int16_t                        ao_flight_pres;         /* filtered pressure */
+__pdata int16_t                        ao_ground_pres;         /* startup pressure */
+__pdata int16_t                        ao_ground_accel;        /* startup acceleration */
+__pdata int16_t                        ao_min_pres;            /* minimum recorded pressure */
+__pdata uint16_t               ao_launch_tick;         /* time of launch detect */
+__pdata int16_t                        ao_main_pres;           /* pressure to eject main */
+
+/*
+ * track min/max data over a long interval to detect
+ * resting
+ */
+__pdata uint16_t               ao_interval_end;
+__pdata int16_t                        ao_interval_cur_min_accel;
+__pdata int16_t                        ao_interval_cur_max_accel;
+__pdata int16_t                        ao_interval_cur_min_pres;
+__pdata int16_t                        ao_interval_cur_max_pres;
+__pdata int16_t                        ao_interval_min_accel;
+__pdata int16_t                        ao_interval_max_accel;
+__pdata int16_t                        ao_interval_min_pres;
+__pdata int16_t                        ao_interval_max_pres;
+
+__data uint8_t ao_flight_adc;
+__pdata int16_t ao_raw_accel, ao_raw_accel_prev, ao_raw_pres;
+
+/* 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
+/* convert m/s to velocity count */
+#define VEL_MPS_TO_COUNT(mps) ((int32_t) (((mps) / GRAVITY) * ACCEL_G * 100))
+
+#define ACCEL_G                265
+#define ACCEL_ZERO_G   16000
+#define ACCEL_NOSE_UP  (ACCEL_G * 2 /3)
+#define ACCEL_BOOST    ACCEL_G * 2
+#define ACCEL_INT_LAND (ACCEL_G / 10)
+#define ACCEL_VEL_LAND VEL_MPS_TO_COUNT(10)
+#define ACCEL_VEL_MACH VEL_MPS_TO_COUNT(200)
+#define ACCEL_VEL_APOGEE       VEL_MPS_TO_COUNT(2)
+#define ACCEL_VEL_MAIN VEL_MPS_TO_COUNT(100)
+#define ACCEL_VEL_BOOST        VEL_MPS_TO_COUNT(5)
+
+/*
+ * 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
+ */
+
+#define BARO_kPa       268
+#define BARO_LAUNCH    (BARO_kPa / 5)  /* .2kPa, or about 20m */
+#define BARO_APOGEE    (BARO_kPa / 10) /* .1kPa, or about 10m */
+#define BARO_COAST     (BARO_kPa * 5)  /* 5kpa, or about 500m */
+#define BARO_MAIN      (BARO_kPa)      /* 1kPa, or about 100m */
+#define BARO_INT_LAND  (BARO_kPa / 20) /* .05kPa, or about 5m */
+#define BARO_LAND      (BARO_kPa * 10) /* 10kPa or about 1000m */
+
+/* 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)
+
+/* This value is scaled in a weird way. It's a running total of accelerometer
+ * readings minus the ground accelerometer reading. That means it measures
+ * velocity, and quite accurately too. As it gets updated 100 times a second,
+ * it's scaled by 100
+ */
+__pdata int32_t        ao_flight_vel;
+__pdata int32_t ao_min_vel;
+__pdata int32_t        ao_old_vel;
+__pdata int16_t ao_old_vel_tick;
+__xdata int32_t ao_raw_accel_sum, ao_raw_pres_sum;
+
+/* 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(20)
+
+#define abs(a) ((a) < 0 ? -(a) : (a))
+
+void
+ao_flight(void)
+{
+       __pdata static uint16_t nsamples = 0;
+
+       ao_flight_adc = ao_adc_head;
+       ao_raw_accel_prev = 0;
+       ao_raw_accel = 0;
+       ao_raw_pres = 0;
+       ao_flight_tick = 0;
+       for (;;) {
+               ao_sleep(&ao_adc_ring);
+               while (ao_flight_adc != ao_adc_head) {
+                       __pdata uint8_t ticks;
+                       __pdata int16_t ao_vel_change;
+                       ao_flight_prev_tick = ao_flight_tick;
+
+                       /* Capture a sample */
+                       ao_raw_accel = ao_adc_ring[ao_flight_adc].accel;
+                       ao_raw_pres = ao_adc_ring[ao_flight_adc].pres;
+                       ao_flight_tick = ao_adc_ring[ao_flight_adc].tick;
+
+                       ao_flight_accel -= ao_flight_accel >> 4;
+                       ao_flight_accel += ao_raw_accel >> 4;
+                       ao_flight_pres -= ao_flight_pres >> 4;
+                       ao_flight_pres += ao_raw_pres >> 4;
+                       /* Update velocity
+                        *
+                        * The accelerometer is mounted so that
+                        * acceleration yields negative values
+                        * while deceleration yields positive values,
+                        * so subtract instead of add.
+                        */
+                       ticks = ao_flight_tick - ao_flight_prev_tick;
+                       ao_vel_change = (((ao_raw_accel >> 1) + (ao_raw_accel_prev >> 1)) - ao_ground_accel);
+                       ao_raw_accel_prev = ao_raw_accel;
+
+                       /* one is a common interval */
+                       if (ticks == 1)
+                               ao_flight_vel -= (int32_t) ao_vel_change;
+                       else
+                               ao_flight_vel -= (int32_t) ao_vel_change * (int32_t) ticks;
+
+                       ao_flight_adc = ao_adc_ring_next(ao_flight_adc);
+               }
+
+               if (ao_flight_pres < ao_min_pres)
+                       ao_min_pres = ao_flight_pres;
+               if (ao_flight_vel >= 0) {
+                       if (ao_flight_vel < ao_min_vel)
+                           ao_min_vel = ao_flight_vel;
+               } else {
+                       if (-ao_flight_vel < ao_min_vel)
+                           ao_min_vel = -ao_flight_vel;
+               }
+
+               switch (ao_flight_state) {
+               case ao_flight_startup:
+
+                       /* startup state:
+                        *
+                        * Collect 1000 samples of acceleration and pressure
+                        * data and average them to find the resting values
+                        */
+                       if (nsamples < 1000) {
+                               ao_raw_accel_sum += ao_raw_accel;
+                               ao_raw_pres_sum += ao_raw_pres;
+                               ++nsamples;
+                               continue;
+                       }
+                       ao_ground_accel = (ao_raw_accel_sum / nsamples);
+                       ao_ground_pres = (ao_raw_pres_sum / nsamples);
+                       ao_min_pres = ao_ground_pres;
+                       ao_config_get();
+                       ao_main_pres = ao_altitude_to_pres(ao_pres_to_altitude(ao_ground_pres) + ao_config.main_deploy);
+                       ao_flight_vel = 0;
+                       ao_min_vel = 0;
+                       ao_old_vel = ao_flight_vel;
+                       ao_old_vel_tick = ao_flight_tick;
+
+                       /* Go to launchpad state if the nose is pointing up */
+                       ao_config_get();
+                       if (ao_flight_accel < ao_config.accel_zero_g - ACCEL_NOSE_UP) {
+
+                               /* Disable the USB controller in flight mode
+                                * to save power
+                                */
+                               ao_usb_disable();
+
+                               /* Turn on telemetry system
+                                */
+                               ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD);
+
+                               ao_flight_state = ao_flight_launchpad;
+                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                       } else {
+                               ao_flight_state = ao_flight_idle;
+
+                               /* Turn on the Green LED in idle mode
+                                */
+                               ao_led_on(AO_LED_GREEN);
+                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                       }
+                       /* signal successful initialization by turning off the LED */
+                       ao_led_off(AO_LED_RED);
+                       break;
+               case ao_flight_launchpad:
+
+                       /* Trim velocity
+                        *
+                        * Once a second, remove any velocity from
+                        * a second ago
+                        */
+                       if ((int16_t) (ao_flight_tick - ao_old_vel_tick) >= AO_SEC_TO_TICKS(1)) {
+                               ao_old_vel_tick = ao_flight_tick;
+                               ao_flight_vel -= ao_old_vel;
+                               ao_old_vel = ao_flight_vel;
+                       }
+                       /* pad to boost:
+                        *
+                        * accelerometer: > 2g AND velocity > 5m/s
+                        *             OR
+                        * barometer: > 20m vertical motion
+                        *
+                        * The accelerometer should always detect motion before
+                        * the barometer, but we use both to make sure this
+                        * transition is detected
+                        */
+                       if ((ao_flight_accel < ao_ground_accel - ACCEL_BOOST &&
+                            ao_flight_vel > ACCEL_VEL_BOOST) ||
+                           ao_flight_pres < ao_ground_pres - BARO_LAUNCH)
+                       {
+                               ao_flight_state = ao_flight_boost;
+                               ao_launch_tick = ao_flight_tick;
+
+                               /* start logging data */
+                               ao_log_start();
+
+                               /* Increase telemetry rate */
+                               ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_FLIGHT);
+
+                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                               break;
+                       }
+                       break;
+               case ao_flight_boost:
+
+                       /* boost to coast:
+                        *
+                        * 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_flight_accel > ao_ground_accel + (ACCEL_G >> 2) ||
+                           (int16_t) (ao_flight_tick - ao_launch_tick) > BOOST_TICKS_MAX)
+                       {
+                               ao_flight_state = ao_flight_coast;
+                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                               break;
+                       }
+                       break;
+               case ao_flight_coast:
+
+                       /* coast to apogee detect:
+                        *
+                        * accelerometer: integrated velocity < 200 m/s
+                        *               OR
+                        * barometer: fall at least 500m from max altitude
+                        *
+                        * This extra state is required to avoid mis-detecting
+                        * apogee due to mach transitions.
+                        *
+                        * XXX this is essentially a single-detector test
+                        * as the 500m altitude change would likely result
+                        * in a loss of the rocket. More data on precisely
+                        * how big a pressure change the mach transition
+                        * generates would be useful here.
+                        */
+                       if (ao_flight_vel < ACCEL_VEL_MACH ||
+                           ao_flight_pres > ao_min_pres + BARO_COAST)
+                       {
+                               /* set min velocity to current velocity for
+                                * apogee detect
+                                */
+                               ao_min_vel = abs(ao_flight_vel);
+                               ao_flight_state = ao_flight_apogee;
+                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                       }
+                       break;
+               case ao_flight_apogee:
+
+                       /* apogee detect to drogue deploy:
+                        *
+                        * accelerometer: abs(velocity) > min_velocity + 2m/s
+                        *               OR
+                        * barometer: fall at least 10m
+                        *
+                        * If the barometer saturates because the flight
+                        * goes over its measuring range (about 53k'),
+                        * requiring a 10m fall will avoid prematurely
+                        * detecting apogee; the accelerometer will take
+                        * over in that case and the integrated velocity
+                        * measurement should suffice to find apogee
+                        */
+                       if (/* abs(ao_flight_vel) > ao_min_vel + ACCEL_VEL_APOGEE || */
+                           ao_flight_pres > ao_min_pres + BARO_APOGEE)
+                       {
+                               /* ignite the drogue charge */
+                               ao_ignite(ao_igniter_drogue);
+
+                               /* slow down the telemetry system */
+                               ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER);
+
+                               /* slow down the ADC sample rate */
+                               ao_timer_set_adc_interval(10);
+
+                               /*
+                                * Start recording min/max accel and pres for a while
+                                * to figure out when the rocket has landed
+                                */
+                               /* Set the 'last' limits to max range to prevent
+                                * early resting detection
+                                */
+                               ao_interval_min_accel = 0;
+                               ao_interval_max_accel = 0x7fff;
+                               ao_interval_min_pres = 0;
+                               ao_interval_max_pres = 0x7fff;
+
+                               /* initialize interval values */
+                               ao_interval_end = ao_flight_tick + AO_INTERVAL_TICKS;
+
+                               ao_interval_cur_min_pres = ao_interval_cur_max_pres = ao_flight_pres;
+                               ao_interval_cur_min_accel = ao_interval_cur_max_accel = ao_flight_accel;
+
+                               /* 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_flight_pres >= ao_main_pres)
+                       {
+                               ao_ignite(ao_igniter_main);
+                               ao_flight_state = ao_flight_main;
+                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                       }
+
+                       /* fall through... */
+               case ao_flight_main:
+
+                       /* drogue/main to land:
+                        *
+                        * accelerometer: value stable
+                        *                           AND
+                        * barometer: altitude stable and within 1000m of the launch altitude
+                        */
+
+                       if (ao_flight_pres < ao_interval_cur_min_pres)
+                               ao_interval_cur_min_pres = ao_flight_pres;
+                       if (ao_flight_pres > ao_interval_cur_max_pres)
+                               ao_interval_cur_max_pres = ao_flight_pres;
+                       if (ao_flight_accel < ao_interval_cur_min_accel)
+                               ao_interval_cur_min_accel = ao_flight_accel;
+                       if (ao_flight_accel > ao_interval_cur_max_accel)
+                               ao_interval_cur_max_accel = ao_flight_accel;
+
+                       if ((int16_t) (ao_flight_tick - ao_interval_end) >= 0) {
+                               ao_interval_max_pres = ao_interval_cur_max_pres;
+                               ao_interval_min_pres = ao_interval_cur_min_pres;
+                               ao_interval_max_accel = ao_interval_cur_max_accel;
+                               ao_interval_min_accel = ao_interval_cur_min_accel;
+                               ao_interval_end = ao_flight_tick + AO_INTERVAL_TICKS;
+                               ao_interval_cur_min_pres = ao_interval_cur_max_pres = ao_flight_pres;
+                               ao_interval_cur_min_accel = ao_interval_cur_max_accel = ao_flight_accel;
+                       }
+
+                       if ((uint16_t) (ao_interval_max_accel - ao_interval_min_accel) < (uint16_t) ACCEL_INT_LAND &&
+                           ao_flight_pres > ao_ground_pres - BARO_LAND &&
+                           (uint16_t) (ao_interval_max_pres - ao_interval_min_pres) < (uint16_t) BARO_INT_LAND)
+                       {
+                               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));
+                       }
+                       break;
+               case ao_flight_landed:
+                       break;
+               }
+       }
+}
+
+#define AO_ACCEL_COUNT_TO_MSS(count)   ((count) / 27)
+#define AO_VEL_COUNT_TO_MS(count)      ((int16_t) ((count) / 2700))
+
+static void
+ao_flight_status(void)
+{
+       printf("STATE: %7s accel: %d speed: %d altitude: %d main: %d\n",
+              ao_state_names[ao_flight_state],
+              AO_ACCEL_COUNT_TO_MSS(ACCEL_ZERO_G - ao_flight_accel),
+              AO_VEL_COUNT_TO_MS(ao_flight_vel),
+              ao_pres_to_altitude(ao_flight_pres),
+              ao_pres_to_altitude(ao_main_pres));
+}
+
+static __xdata struct ao_task  flight_task;
+
+__code struct ao_cmds ao_flight_cmds[] = {
+       { 'f', ao_flight_status,        "f                                  Display current flight state" },
+       { 0, ao_flight_status, NULL }
+};
+
+void
+ao_flight_init(void)
+{
+       ao_flight_state = ao_flight_startup;
+       ao_interval_min_accel = 0;
+       ao_interval_max_accel = 0x7fff;
+       ao_interval_min_pres = 0;
+       ao_interval_max_pres = 0x7fff;
+       ao_interval_end = AO_INTERVAL_TICKS;
+
+       ao_add_task(&flight_task, ao_flight, "flight");
+       ao_cmd_register(&ao_flight_cmds[0]);
+}
diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c
new file mode 100644 (file)
index 0000000..f4731aa
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * 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>
+
+#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_launchpad = 2,
+       ao_flight_boost = 3,
+       ao_flight_coast = 4,
+       ao_flight_apogee = 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()
+#define ao_cmd_register(c)
+#define ao_usb_disable()
+#define ao_telemetry_set_interval(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);
+
+void
+ao_sleep(void *wchan);
+
+const char const * const ao_state_names[] = {
+       "startup", "idle", "pad", "boost", "coast",
+       "apogee", "drogue", "main", "landed", "invalid"
+};
+
+struct ao_cmds {
+       char            cmd;
+       void            (*func)(void);
+       const char      *help;
+};
+
+
+static int16_t altitude_table[2048] = {
+#include "altitude.h"
+};
+
+int16_t
+ao_pres_to_altitude(int16_t pres) __reentrant
+{
+       pres = pres >> 4;
+       if (pres < 0) pres = 0;
+       if (pres > 2047) pres = 2047;
+       return altitude_table[pres];
+}
+
+int16_t
+ao_altitude_to_pres(int16_t alt) __reentrant
+{
+       int16_t pres;
+
+       for (pres = 0; pres < 2047; pres++)
+               if (altitude_table[pres] <= alt)
+                       break;
+       return pres << 4;
+}
+
+struct ao_config {
+       uint16_t        main_deploy;
+       int16_t         accel_zero_g;
+};
+
+#define ao_config_get()
+
+struct ao_config ao_config = { 250, 16000 };
+
+#include "ao_flight.c"
+
+void
+ao_insert(void)
+{
+       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) {
+               printf("time %g accel %d pres %d\n",
+                      (double) ao_adc_static.tick / 100,
+                      ao_adc_static.accel,
+                      ao_adc_static.pres);
+       }
+}
+
+static int     ao_records_read = 0;
+static int     ao_eof_read = 0;
+static int     ao_flight_ground_accel;
+static int     ao_flight_started = 0;
+
+void
+ao_sleep(void *wchan)
+{
+       ao_dump_state();
+       if (wchan == &ao_adc_ring) {
+               char            type;
+               uint16_t        tick;
+               uint16_t        a, b;
+               int             ret;
+               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) {
+                                       printf ("no more data, exiting simulation\n");
+                                       exit(0);
+                               }
+                               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[2], NULL, 16);
+                       } 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]);
+                               }
+                       }
+                       if (type != 'F' && !ao_flight_started)
+                               continue;
+
+                       switch (type) {
+                       case 'F':
+                               ao_flight_ground_accel = a;
+                               ao_flight_started = 1;
+                               break;
+                       case 'S':
+                               break;
+                       case 'A':
+                               ao_adc_static.tick = tick;
+                               ao_adc_static.accel = a;
+                               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)
+{
+       if (ao_flight_state == ao_flight_startup)
+               return;
+       printf ("\t\t\t\t\t%s accel %g vel %g alt %d main %d\n",
+               ao_state_names[ao_flight_state],
+               (ao_ground_accel - ao_flight_accel) / COUNTS_PER_G * GRAVITY,
+               (double) ao_flight_vel / 100 / COUNTS_PER_G * GRAVITY,
+               ao_pres_to_altitude(ao_flight_pres) - ao_pres_to_altitude(ao_ground_pres),
+               ao_pres_to_altitude(ao_main_pres) - ao_pres_to_altitude(ao_ground_pres));
+       if (ao_flight_state == ao_flight_landed)
+               exit(0);
+}
+
+int
+main (int argc, char **argv)
+{
+       emulator_in = fopen (argv[1], "r");
+       if (!emulator_in) {
+               perror(argv[1]);
+               exit(1);
+       }
+       ao_flight_init();
+       ao_flight();
+}
diff --git a/src/ao_gps.c b/src/ao_gps.c
new file mode 100644 (file)
index 0000000..cbde8b4
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * 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_GPS_LEADER          6
+
+static const char ao_gps_header[] = "GPGGA,";
+__xdata uint8_t ao_gps_mutex;
+static __xdata char ao_gps_char;
+static __xdata uint8_t ao_gps_cksum;
+static __xdata uint8_t ao_gps_error;
+
+__xdata struct ao_gps_data     ao_gps_data;
+static __xdata struct ao_gps_data      ao_gps_next;
+
+const char ao_gps_config[] =
+       "$PSRF103,00,00,01,01*25\r\n"   /* GGA 1 per sec */
+       "$PSRF103,01,00,00,01*25\r\n"   /* GLL disable */
+       "$PSRF103,02,00,00,01*26\r\n"   /* GSA disable */
+       "$PSRF103,03,00,00,01*27\r\n"   /* GSV disable */
+       "$PSRF103,04,00,00,01*20\r\n"   /* RMC disable */
+       "$PSRF103,05,00,00,01*21\r\n";  /* VTG disable */
+
+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(void)
+{
+       while (ao_gps_char >= '0')
+               ao_gps_lexchar();
+}
+
+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)
+{
+       while (ao_gps_char == ',' || ao_gps_char == '.' || ao_gps_char == '*')
+               ao_gps_lexchar();
+}
+
+__xdata static uint8_t ao_gps_num_width;
+
+static int16_t
+ao_gps_decimal(uint8_t max_width)
+{
+       int16_t v;
+       __xdata 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 void
+ao_gps_parse_pos(__xdata struct ao_gps_pos * pos, uint8_t deg_width) __reentrant
+{
+       pos->degrees = ao_gps_decimal(deg_width);
+       pos->minutes = ao_gps_decimal(2);
+       if (ao_gps_char == '.') {
+               pos->minutes_fraction = ao_gps_decimal(4);
+               while (ao_gps_num_width < 4) {
+                       pos->minutes_fraction *= 10;
+                       ao_gps_num_width++;
+               }
+       } else {
+               pos->minutes_fraction = 0;
+               if (ao_gps_char != ',')
+                       ao_gps_error = 1;
+       }
+}
+
+static void
+ao_gps_parse_flag(char yes_c, uint8_t yes, char no_c, uint8_t no) __reentrant
+{
+       ao_gps_skip_sep();
+       if (ao_gps_char == yes_c)
+               ao_gps_next.flags |= yes;
+       else if (ao_gps_char == no_c)
+               ao_gps_next.flags |= no;
+       else
+               ao_gps_error = 1;
+       ao_gps_lexchar();
+}
+
+
+void
+ao_gps(void) __reentrant
+{
+       char    c;
+       uint8_t i;
+
+       for (i = 0; (c = ao_gps_config[i]); i++)
+               ao_serial_putchar(c);
+       for (;;) {
+               /* Locate the begining of the next record */
+               for (;;) {
+                       c = ao_serial_getchar();
+                       if (c == '$')
+                               break;
+               }
+
+               ao_gps_cksum = 0;
+               ao_gps_error = 0;
+
+               /* Skip anything other than GGA */
+               for (i = 0; i < AO_GPS_LEADER; i++) {
+                       ao_gps_lexchar();
+                       if (ao_gps_char != ao_gps_header[i])
+                               break;
+               }
+               if (i != AO_GPS_LEADER)
+                       continue;
+
+               /* 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.flags = 0;
+               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_parse_pos(&ao_gps_next.latitude, 2);
+               ao_gps_parse_flag('N', AO_GPS_LATITUDE_NORTH, 'S', AO_GPS_LATITUDE_SOUTH);
+               ao_gps_parse_pos(&ao_gps_next.longitude, 3);
+               ao_gps_parse_flag('W', AO_GPS_LONGITUDE_WEST, 'E', AO_GPS_LONGITUDE_EAST);
+
+               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();
+               ao_gps_skip_field();    /* Horizontal dilution */
+
+               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);
+                       memcpy(&ao_gps_data, &ao_gps_next, sizeof (struct ao_gps_data));
+                       ao_mutex_put(&ao_gps_mutex);
+                       ao_wakeup(&ao_gps_data);
+               }
+       }
+}
+
+__xdata struct ao_task ao_gps_task;
+
+static void
+gps_dump(void) __reentrant
+{
+       ao_mutex_get(&ao_gps_mutex);
+       ao_gps_print(&ao_gps_data);
+       ao_mutex_put(&ao_gps_mutex);
+}
+
+__code struct ao_cmds ao_gps_cmds[] = {
+       { 'g', gps_dump,        "g                                  Display current GPS values" },
+       { 0, gps_dump, NULL },
+};
+
+void
+ao_gps_init(void)
+{
+       ao_add_task(&ao_gps_task, ao_gps, "gps");
+       ao_cmd_register(&ao_gps_cmds[0]);
+}
diff --git a/src/ao_gps_print.c b/src/ao_gps_print.c
new file mode 100644 (file)
index 0000000..7e157db
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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_print(__xdata struct ao_gps_data *gps_data) __reentrant
+{
+       printf("GPS %2d sat",
+              (gps_data->flags & AO_GPS_NUM_SAT_MASK) >> AO_GPS_NUM_SAT_SHIFT);;
+       if (gps_data->flags & AO_GPS_VALID) {
+               printf(" %2d:%02d:%02d %2d°%2d.%04d'%c %2d°%2d.%04d'%c %5dm\n",
+                      gps_data->hour,
+                      gps_data->minute,
+                      gps_data->second,
+                      gps_data->latitude.degrees,
+                      gps_data->latitude.minutes,
+                      gps_data->latitude.minutes_fraction,
+                      (gps_data->flags & AO_GPS_LATITUDE_MASK) == AO_GPS_LATITUDE_NORTH ?
+                      'N' : 'S',
+                      gps_data->longitude.degrees,
+                      gps_data->longitude.minutes,
+                      gps_data->longitude.minutes_fraction,
+                      (gps_data->flags & AO_GPS_LONGITUDE_MASK) == AO_GPS_LONGITUDE_WEST ?
+                      'W' : 'E',
+                      gps_data->altitude,
+                      (gps_data->flags & AO_GPS_NUM_SAT_MASK) >> AO_GPS_NUM_SAT_SHIFT);
+       } else {
+               printf(" unlocked\n");
+       }
+}
diff --git a/src/ao_gps_report.c b/src/ao_gps_report.c
new file mode 100644 (file)
index 0000000..1b5402a
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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_gps_data       gps_data;
+
+       for (;;) {
+               ao_sleep(&ao_gps_data);
+               ao_mutex_get(&ao_gps_mutex);
+               memcpy(&gps_data, &ao_gps_data, sizeof (struct ao_gps_data));
+               ao_mutex_put(&ao_gps_mutex);
+
+               if (!(gps_data.flags & AO_GPS_VALID))
+                       continue;
+
+               gps_log.tick = ao_time();
+               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.degrees = gps_data.latitude.degrees;
+               gps_log.u.gps_latitude.minutes = gps_data.latitude.minutes;
+               gps_log.u.gps_latitude.minutes_fraction = gps_data.latitude.minutes_fraction;
+               ao_log_data(&gps_log);
+               gps_log.type = AO_LOG_GPS_LON;
+               gps_log.u.gps_longitude.degrees = gps_data.longitude.degrees;
+               gps_log.u.gps_longitude.minutes = gps_data.longitude.minutes;
+               gps_log.u.gps_longitude.minutes_fraction = gps_data.longitude.minutes_fraction;
+               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);
+       }
+}
+
+__xdata struct ao_task ao_gps_report_task;
+
+void
+ao_gps_report_init(void)
+{
+       ao_add_task(&ao_gps_report_task, ao_gps_report, "gps_report");
+}
diff --git a/src/ao_ignite.c b/src/ao_ignite.c
new file mode 100644 (file)
index 0000000..be29152
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * 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_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)
+
+/* 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(500)
+#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[0]);
+}
+
+enum ao_igniter_status
+ao_igniter_status(enum ao_igniter igniter)
+{
+       __xdata struct ao_adc adc;
+       __xdata int16_t value;
+       __xdata uint8_t request, firing, fired;
+
+       __critical {
+               ao_adc_sleep();
+               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 (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;
+       }
+       ao_ignition[igniter].firing = 0;
+}
+
+void
+ao_igniter(void)
+{
+       __xdata enum ao_ignter igniter;
+       __xdata enum ao_igniter_status status;
+
+       for (;;) {
+               ao_sleep(&ao_ignition);
+               for (igniter = ao_igniter_drogue; igniter <= ao_igniter_main; igniter++) {
+                       if (ao_ignition[igniter].request && !ao_ignition[igniter].fired) {
+                               ao_igniter_fire(igniter);
+                               ao_delay(AO_IGNITER_CHARGE_TIME);
+                               status = ao_igniter_status(igniter);
+                               if (status == ao_igniter_open)
+                                       ao_ignition[igniter].fired = 1;
+                       }
+               }
+       }
+}
+
+static 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;
+}
+
+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 *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[] = {
+       { 'i',  ao_ignite_manual,       "i <key> {main|drogue}              Fire igniter. <key> is doit with D&I" },
+       { 't',  ao_ignite_test,         "t                                  Test igniter continuity" },
+       { 0,    ao_ignite_manual,       NULL },
+};
+
+__xdata struct ao_task ao_igniter_task;
+
+void
+ao_igniter_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_ignite_cmds[0]);
+       ao_add_task(&ao_igniter_task, ao_igniter, "igniter");
+}
diff --git a/src/ao_led.c b/src/ao_led.c
new file mode 100644 (file)
index 0000000..6c698b4
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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_LED_ALL     (AO_LED_GREEN|AO_LED_RED)
+
+__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;
+}
diff --git a/src/ao_log.c b/src/ao_log.c
new file mode 100644 (file)
index 0000000..19bfdfb
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * 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 __pdata uint32_t        ao_log_current_pos;
+static __pdata uint32_t        ao_log_start_pos;
+static __xdata uint8_t ao_log_running;
+static __xdata uint8_t ao_log_mutex;
+
+static uint8_t
+ao_log_csum(uint8_t *b)
+{
+       uint8_t sum = 0x5a;
+       uint8_t i;
+
+       for (i = 0; i < sizeof (struct ao_log_record); i++)
+               sum += *b++;
+       return -sum;
+}
+
+void
+ao_log_data(struct ao_log_record *log)
+{
+       /* set checksum */
+       log->csum = 0;
+       log->csum = ao_log_csum((uint8_t *) log);
+       ao_mutex_get(&ao_log_mutex); {
+               if (ao_log_running) {
+                       ao_ee_write(ao_log_current_pos,
+                                   (uint8_t *) log,
+                                   sizeof (struct ao_log_record));
+                       ao_log_current_pos += sizeof (struct ao_log_record);
+                       if (ao_log_current_pos >= AO_EE_DATA_SIZE)
+                               ao_log_current_pos = 0;
+                       if (ao_log_current_pos == ao_log_start_pos)
+                               ao_log_running = 0;
+               }
+       } ao_mutex_put(&ao_log_mutex);
+}
+
+void
+ao_log_flush(void)
+{
+       ao_ee_flush();
+}
+
+__xdata struct ao_log_record ao_log_dump;
+static __xdata uint16_t ao_log_dump_flight;
+static __xdata uint32_t ao_log_dump_pos;
+
+static uint8_t
+ao_log_dump_check_data(void)
+{
+       if (ao_log_csum((uint8_t *) &ao_log_dump) != 0)
+               return 0;
+       return 1;
+}
+
+static uint8_t
+ao_log_dump_scan(void)
+{
+       if (!ao_ee_read(0, (uint8_t *) &ao_log_dump, sizeof (struct ao_log_record)))
+               ao_panic(AO_PANIC_LOG);
+       if (ao_log_dump_check_data() && ao_log_dump.type == AO_LOG_FLIGHT) {
+               ao_log_dump_flight = ao_log_dump.u.flight.flight;
+               return 1;
+       } else {
+               ao_log_dump_flight = 0;
+               return 0;
+       }
+}
+
+uint8_t
+ao_log_dump_first(void)
+{
+       ao_log_dump_pos = 0;
+       if (!ao_log_dump_scan())
+               return 0;
+       return 1;
+}
+
+uint8_t
+ao_log_dump_next(void)
+{
+       ao_log_dump_pos += sizeof (struct ao_log_record);
+       if (ao_log_dump_pos >= AO_EE_DEVICE_SIZE)
+               return 0;
+       if (!ao_ee_read(ao_log_dump_pos, (uint8_t *) &ao_log_dump,
+                       sizeof (struct ao_log_record)))
+               return 0;
+       return ao_log_dump_check_data();
+}
+
+__xdata uint8_t        ao_log_adc_pos;
+__xdata enum flight_state ao_log_state;
+
+void
+ao_log(void)
+{
+       static __xdata struct ao_log_record     log;
+
+       ao_log_dump_scan();
+
+       while (!ao_log_running)
+               ao_sleep(&ao_log_running);
+
+       log.type = AO_LOG_FLIGHT;
+       log.tick = ao_flight_tick;
+       log.u.flight.ground_accel = ao_ground_accel;
+       log.u.flight.flight = ao_log_dump_flight + 1;
+       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_adc_head);
+       for (;;) {
+               /* Write samples to EEPROM */
+               while (ao_log_adc_pos != ao_adc_head) {
+                       log.type = AO_LOG_SENSOR;
+                       log.tick = ao_adc_ring[ao_log_adc_pos].tick;
+                       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_adc_pos & 0x1f) == 0) {
+                               log.type = AO_LOG_TEMP_VOLT;
+                               log.tick = ao_adc_ring[ao_log_adc_pos].tick;
+                               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.tick = ao_adc_ring[ao_log_adc_pos].tick;
+                               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);
+                       }
+                       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_flight_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);
+       }
+}
+
+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();
+}
+
+static void
+dump_log(void)
+{
+       uint8_t more;
+
+       for (more = ao_log_dump_first(); more; more = ao_log_dump_next()) {
+               printf("%c %4x %4x %4x\n",
+                      ao_log_dump.type,
+                      ao_log_dump.tick,
+                      ao_log_dump.u.anon.d0,
+                      ao_log_dump.u.anon.d1);
+               if (ao_log_dump.type == AO_LOG_STATE &&
+                   ao_log_dump.u.state.state == ao_flight_landed)
+                       break;
+       }
+       printf("end\n");
+}
+
+__code struct ao_cmds ao_log_cmds[] = {
+       { 'l',  dump_log,               "l                                  Dump last flight log" },
+       { 0, dump_log, NULL },
+};
+
+static __xdata struct ao_task ao_log_task;
+
+void
+ao_log_init(void)
+{
+       ao_log_running = 0;
+
+       /* For now, just log the flight starting at the begining of eeprom */
+       ao_log_start_pos = 0;
+       ao_log_current_pos = ao_log_start_pos;
+       ao_log_state = ao_flight_invalid;
+
+       /* Create a task to log events to eeprom */
+       ao_add_task(&ao_log_task, ao_log, "log");
+       ao_cmd_register(&ao_log_cmds[0]);
+}
diff --git a/src/ao_main.c b/src/ao_main.c
new file mode 100644 (file)
index 0000000..1f7a829
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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)
+{
+       CLKCON = 0;
+       while (!(SLEEP & SLEEP_XOSC_STB))
+               ;
+
+       /* 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();
+}
diff --git a/src/ao_monitor.c b/src/ao_monitor.c
new file mode 100644 (file)
index 0000000..5997d42
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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 uint8_t ao_monitoring;
+__pdata uint8_t ao_monitor_led;
+
+void
+ao_monitor(void)
+{
+       __xdata struct ao_radio_recv recv;
+       __xdata char callsign[AO_MAX_CALLSIGN+1];
+       uint8_t state;
+
+       for (;;) {
+               __critical while (!ao_monitoring)
+                       ao_sleep(&ao_monitoring);
+               ao_radio_recv(&recv);
+               state = recv.telemetry.flight_state;
+               memcpy(callsign, recv.telemetry.callsign, AO_MAX_CALLSIGN);
+               if (state > ao_flight_invalid)
+                       state = ao_flight_invalid;
+               if (recv.status & PKT_APPEND_STATUS_1_CRC_OK) {
+                       printf ("CALL %s SERIAL %3d RSSI %4d STATUS %02x STATE %7s ",
+                               callsign,
+                               recv.telemetry.addr,
+                               (int) recv.rssi - 74, recv.status,
+                               ao_state_names[state]);
+                       printf("%5u a: %5d p: %5d t: %5d v: %5d d: %5d m: %5d fa: %5d ga: %d fv: %7ld fp: %5d gp: %5d ",
+                              recv.telemetry.adc.tick,
+                              recv.telemetry.adc.accel,
+                              recv.telemetry.adc.pres,
+                              recv.telemetry.adc.temp,
+                              recv.telemetry.adc.v_batt,
+                              recv.telemetry.adc.sense_d,
+                              recv.telemetry.adc.sense_m,
+                              recv.telemetry.flight_accel,
+                              recv.telemetry.ground_accel,
+                              recv.telemetry.flight_vel,
+                              recv.telemetry.flight_pres,
+                              recv.telemetry.ground_pres);
+                       ao_gps_print(&recv.telemetry.gps);
+                       ao_rssi_set((int) recv.rssi - 74);
+               } else {
+                       printf("CRC INVALID RSSI %3d\n", (int) recv.rssi - 74);
+               }
+               ao_usb_flush();
+               ao_led_toggle(ao_monitor_led);
+       }
+}
+
+__xdata struct ao_task ao_monitor_task;
+
+void
+ao_set_monitor(uint8_t monitoring)
+{
+       ao_monitoring = monitoring;
+       ao_wakeup(&ao_monitoring);
+}
+
+static void
+set_monitor(void)
+{
+       ao_cmd_hex();
+       ao_set_monitor(ao_cmd_lex_i != 0);
+}
+
+__code struct ao_cmds ao_monitor_cmds[] = {
+       { 'm',  set_monitor,    "m <0 off, 1 on>                    Enable/disable radio monitoring" },
+       { 0,    set_monitor,    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_task, ao_monitor, "monitor");
+}
diff --git a/src/ao_mutex.c b/src/ao_mutex.c
new file mode 100644 (file)
index 0000000..c82a7d5
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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);
+       }
+}
diff --git a/src/ao_panic.c b/src/ao_panic.c
new file mode 100644 (file)
index 0000000..e996371
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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 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);
+               }
+       }
+}
diff --git a/src/ao_product.c b/src/ao_product.c
new file mode 100644 (file)
index 0000000..b42e62c
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * 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"
+#include PRODUCT_DEFS
+
+/* Defines which mark this particular AltOS product */
+
+const uint16_t ao_serial_number = AO_iSerial_NUMBER;
+const char ao_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))
+
+/* USB descriptors in one giant block of bytes */
+const 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(0x000A),        /*  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
+};
diff --git a/src/ao_radio.c b/src/ao_radio.c
new file mode 100644 (file)
index 0000000..ca1ec7e
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * 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 434.550MHz, the frequency value is:
+ *
+ * 434.550e6 / (24e6 / 2**16) = 1186611.2
+ */
+
+#define FREQ_CONTROL   1186611
+
+/*
+ * 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
+
+/* 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_FREQ2_OFF,           (FREQ_CONTROL >> 16) & 0xff,
+       RF_FREQ1_OFF,           (FREQ_CONTROL >> 8) & 0xff,
+       RF_FREQ0_OFF,           (FREQ_CONTROL >> 0) & 0xff,
+
+       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_PKTLEN_OFF,          sizeof (struct ao_telemetry),
+
+       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 telemetry_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 */
+       RF_PKTLEN_OFF,          sizeof (struct ao_telemetry),
+       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_mutex;
+
+static void
+ao_radio_idle(void)
+{
+       if (RF_MARCSTATE != RF_MARCSTATE_IDLE)
+       {
+               RFST = RFST_SIDLE;
+               do {
+                       ao_yield();
+               } while (RF_MARCSTATE != RF_MARCSTATE_IDLE);
+       }
+}
+
+void
+ao_radio_send(__xdata struct ao_telemetry *telemetry) __reentrant
+{
+       ao_config_get();
+       ao_mutex_get(&ao_radio_mutex);
+       ao_radio_idle();
+       RF_CHANNR = ao_config.radio_channel;
+       ao_dma_set_transfer(ao_radio_dma,
+                           telemetry,
+                           &RFDXADDR,
+                           sizeof (struct ao_telemetry),
+                           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_dma_done)
+               ao_sleep(&ao_radio_dma_done);
+       ao_mutex_put(&ao_radio_mutex);
+}
+
+void
+ao_radio_recv(__xdata struct ao_radio_recv *radio) __reentrant
+{
+       ao_config_get();
+       ao_mutex_get(&ao_radio_mutex);
+       ao_radio_idle();
+       RF_CHANNR = ao_config.radio_channel;
+       ao_dma_set_transfer(ao_radio_dma,
+                           &RFDXADDR,
+                           radio,
+                           sizeof (struct ao_radio_recv),
+                           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;
+       __critical while (!ao_radio_dma_done)
+               ao_sleep(&ao_radio_dma_done);
+       ao_mutex_put(&ao_radio_mutex);
+}
+
+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_dma_done = 1;
+       ao_radio_dma = ao_dma_alloc(&ao_radio_dma_done);
+}
diff --git a/src/ao_report.c b/src/ao_report.c
new file mode 100644 (file)
index 0000000..e52b292
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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 const char * __xdata flight_reports[] = {
+       "...",          /* startup, 'S' */
+       "..",           /* idle 'I' */
+       ".--.",         /* launchpad 'P' */
+       "-...",         /* boost 'B' */
+       "-.-.",         /* coast 'C' */
+       ".-",           /* apogee 'A' */
+       "-..",          /* drogue 'D' */
+       "--",           /* main 'M' */
+       ".-..",         /* landed 'L' */
+       ".-.-.-",       /* invalid */
+};
+
+#if 1
+#define signal(time)   ao_beep_for(AO_BEEP_MID, time)
+#else
+#define signal(time)   ao_led_for(AO_LED_RED, time)
+#endif
+#define pause(time)    ao_delay(time)
+
+static __xdata enum ao_flight_state ao_report_state;
+
+static void
+ao_report_beep(void) __reentrant
+{
+       char *r = flight_reports[ao_flight_state];
+       char c;
+
+       if (!r)
+               return;
+       while (c = *r++) {
+               if (c == '.')
+                       signal(AO_MS_TO_TICKS(200));
+               else
+                       signal(AO_MS_TO_TICKS(600));
+               pause(AO_MS_TO_TICKS(200));
+       }
+       pause(AO_MS_TO_TICKS(400));
+}
+
+static void
+ao_report_digit(uint8_t digit) __reentrant
+{
+       if (!digit) {
+               signal(AO_MS_TO_TICKS(500));
+               pause(AO_MS_TO_TICKS(200));
+       } else {
+               while (digit--) {
+                       signal(AO_MS_TO_TICKS(200));
+                       pause(AO_MS_TO_TICKS(200));
+               }
+       }
+       pause(AO_MS_TO_TICKS(300));
+}
+
+static void
+ao_report_altitude(void)
+{
+       __xdata int16_t agl = ao_pres_to_altitude(ao_min_pres) - ao_pres_to_altitude(ao_ground_pres);
+       __xdata uint8_t digits[10];
+       __xdata 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));
+       }
+}
+
+void
+ao_report(void)
+{
+       ao_report_state = ao_flight_state;
+       for(;;) {
+               if (ao_flight_state == ao_flight_landed)
+                       ao_report_altitude();
+               ao_report_beep();
+               __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");
+}
diff --git a/src/ao_rssi.c b/src/ao_rssi.c
new file mode 100644 (file)
index 0000000..6912b9a
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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 __xdata volatile uint16_t       ao_rssi_delay;
+static __xdata 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");
+}
diff --git a/src/ao_serial.c b/src/ao_serial.c
new file mode 100644 (file)
index 0000000..ce11694
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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);
+}
+
+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;
+}
+
+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();
+}
+
+static void
+send_serial(void)
+{
+       ao_cmd_white();
+       while (ao_cmd_lex_c != '\n') {
+               ao_serial_putchar(ao_cmd_lex_c);
+               ao_cmd_lex();
+       }
+}
+
+__code struct ao_cmds ao_serial_cmds[] = {
+       { 'S', send_serial,             "S <data>                           Send data to serial line" },
+       { 0, send_serial, NULL },
+};
+
+void
+ao_serial_init(void)
+{
+       /* Set up the USART pin assignment */
+       PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_2;
+
+       /* ee has already set the P2SEL bits */
+
+       /* Make the USART pins be controlled by the USART */
+       P1SEL |= (1 << 6) | (1 << 7);
+
+       /* UART mode with receiver enabled */
+       U1CSR = (UxCSR_MODE_UART | UxCSR_RE);
+
+       /* Pick a 4800 baud rate */
+       U1BAUD = 163;                           /* 4800 */
+       U1GCR = 7 << UxGCR_BAUD_E_SHIFT;        /* 4800 */
+
+       /* Reasonable serial parameters */
+       U1UCR = (UxUCR_FLUSH |
+                UxUCR_FLOW_DISABLE |
+                UxUCR_D9_ODD_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;
+
+       ao_cmd_register(&ao_serial_cmds[0]);
+}
diff --git a/src/ao_state.c b/src/ao_state.c
new file mode 100644 (file)
index 0000000..96b4c1a
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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", "coast",
+       "apogee", "drogue", "main", "landed", "invalid"
+};
diff --git a/src/ao_stdio.c b/src/ao_stdio.c
new file mode 100644 (file)
index 0000000..fb8ce09
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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
+ */
+
+void
+putchar(char c)
+{
+       if (c == '\n')
+               ao_usb_putchar('\r');
+       ao_usb_putchar(c);
+}
+
+void
+flush(void)
+{
+       ao_usb_flush();
+}
+
+char
+getchar(void)
+{
+       return ao_usb_getchar();
+}
diff --git a/src/ao_task.c b/src/ao_task.c
new file mode 100644 (file)
index 0000000..12b7394
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * 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;
+       if (ao_num_tasks == AO_NUM_TASKS)
+               ao_panic(AO_PANIC_NO_TASK);
+       ao_tasks[ao_num_tasks++] = task;
+       task->task_id = ao_num_tasks;
+       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);
+       *stack++ = ((uint16_t) start) >> 8;
+
+       /* and the stuff saved by ao_switch */
+       *stack++ = 0;           /* acc */
+       *stack++ = 0x80;        /* IE */
+       *stack++ = 0;           /* DPL */
+       *stack++ = 0;           /* DPH */
+       *stack++ = 0;           /* B */
+       *stack++ = 0;           /* R2 */
+       *stack++ = 0;           /* R3 */
+       *stack++ = 0;           /* R4 */
+       *stack++ = 0;           /* R5 */
+       *stack++ = 0;           /* R6 */
+       *stack++ = 0;           /* R7 */
+       *stack++ = 0;           /* R0 */
+       *stack++ = 0;           /* R1 */
+       *stack++ = 0;           /* PSW */
+       *stack++ = 0;           /* BP */
+       task->stack_count = stack - task->stack;
+       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)
+       {
+               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;
+                       }
+
+                       /* 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;
+}
+
+void
+ao_sleep(__xdata void *wchan)
+{
+       __critical {
+               ao_cur_task->wchan = wchan;
+       }
+       ao_yield();
+}
+
+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_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();
+}
diff --git a/src/ao_teledongle.c b/src/ao_teledongle.c
new file mode 100644 (file)
index 0000000..567751c
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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)
+{
+       CLKCON = 0;
+       while (!(SLEEP & SLEEP_XOSC_STB))
+               ;
+
+       /* Turn on the 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_cmd_init();
+       ao_usb_init();
+       ao_monitor_init(AO_LED_GREEN, TRUE);
+       ao_rssi_init(AO_LED_RED);
+       ao_radio_init();
+       ao_dbg_init();
+       ao_config_init();
+       ao_start_scheduler();
+}
diff --git a/src/ao_telemetrum.c b/src/ao_telemetrum.c
new file mode 100644 (file)
index 0000000..a680ce1
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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)
+{
+       CLKCON = 0;
+       while (!(SLEEP & SLEEP_XOSC_STB))
+               ;
+
+       /* 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_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_gps_report_init();
+       ao_telemetry_init();
+       ao_radio_init();
+       ao_igniter_init();
+       ao_dbg_init();
+       ao_config_init();
+       ao_start_scheduler();
+}
diff --git a/src/ao_telemetry.c b/src/ao_telemetry.c
new file mode 100644 (file)
index 0000000..463bcd9
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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 uint16_t ao_telemetry_interval = 0;
+
+void
+ao_telemetry(void)
+{
+       static __xdata struct ao_telemetry telemetry;
+
+       ao_config_get();
+       memcpy(telemetry.callsign, ao_config.callsign, AO_MAX_CALLSIGN);
+       telemetry.addr = ao_serial_number;
+       for (;;) {
+               while (ao_telemetry_interval == 0)
+                       ao_sleep(&ao_telemetry_interval);
+               telemetry.flight_state = ao_flight_state;
+               telemetry.flight_accel = ao_flight_accel;
+               telemetry.ground_accel = ao_ground_accel;
+               telemetry.flight_vel = ao_flight_vel;
+               telemetry.flight_pres = ao_flight_pres;
+               telemetry.ground_pres = ao_ground_pres;
+               ao_adc_get(&telemetry.adc);
+               ao_mutex_get(&ao_gps_mutex);
+               memcpy(&telemetry.gps, &ao_gps_data, sizeof (struct ao_gps_data));
+               ao_mutex_put(&ao_gps_mutex);
+               ao_radio_send(&telemetry);
+               ao_delay(ao_telemetry_interval);
+       }
+}
+
+void
+ao_telemetry_set_interval(uint16_t interval)
+{
+       ao_telemetry_interval = interval;
+       ao_wakeup(&ao_telemetry_interval);
+}
+
+__xdata struct ao_task ao_telemetry_task;
+
+void
+ao_telemetry_init()
+{
+       ao_add_task(&ao_telemetry_task, ao_telemetry, "telemetry");
+}
diff --git a/src/ao_teleterra.c b/src/ao_teleterra.c
new file mode 100644 (file)
index 0000000..ad3e2d9
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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)
+{
+       CLKCON = 0;
+       while (!(SLEEP & SLEEP_XOSC_STB))
+               ;
+
+       /* 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_gps_init();
+       ao_monitor_init(AO_LED_GREEN, TRUE);
+       ao_radio_init();
+       ao_dbg_init();
+       ao_config_init();
+       ao_start_scheduler();
+}
diff --git a/src/ao_test.c b/src/ao_test.c
new file mode 100644 (file)
index 0000000..c9bb02a
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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_ring);
+               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)
+{
+       CLKCON = 0;
+       while (!(SLEEP & SLEEP_XOSC_STB))
+               ;
+
+//     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();
+}
diff --git a/src/ao_tidongle.c b/src/ao_tidongle.c
new file mode 100644 (file)
index 0000000..6dfa9ae
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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)
+{
+       CLKCON = 0;
+       while (!(SLEEP & SLEEP_XOSC_STB))
+               ;
+
+       /* 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();
+}
diff --git a/src/ao_timer.c b/src/ao_timer.c
new file mode 100644 (file)
index 0000000..81c3b37
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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;
+}
+
+void
+ao_delay(uint16_t ticks)
+{
+       uint16_t until = ao_time() + ticks;
+
+       while ((int16_t) (until - ao_time()) > 0)
+               ao_sleep(DATA_TO_XDATA(&ao_tick_count));
+}
+
+#define T1_CLOCK_DIVISOR       8       /* 24e6/8 = 3e6 */
+#define T1_SAMPLE_TIME         30000   /* 3e6/30000 = 100 */
+
+volatile __data uint8_t        ao_adc_interval = 1;
+volatile __data uint8_t        ao_adc_count;
+
+void ao_timer_isr(void) interrupt 9
+{
+       ++ao_tick_count;
+       if (++ao_adc_count == ao_adc_interval) {
+               ao_adc_count = 0;
+               ao_adc_poll();
+       }
+       ao_wakeup(DATA_TO_XDATA(&ao_tick_count));
+}
+
+void
+ao_timer_set_adc_interval(uint8_t interval) __critical
+{
+       ao_adc_interval = interval;
+       ao_adc_count = 0;
+}
+
+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;
+}
diff --git a/src/ao_usb.c b/src/ao_usb.c
new file mode 100644 (file)
index 0000000..99f0715
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+ * 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 __xdata uint16_t        ao_usb_out_bytes;
+static __xdata uint8_t ao_usb_iif;
+static __xdata 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_usb_out_bytes);
+
+       if (USBCIF & USBCIF_RSTIF)
+               ao_usb_set_interrupts();
+}
+
+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;
+
+__xdata uint8_t ao_usb_ep0_state;
+uint8_t * __xdata ao_usb_ep0_in_data;
+__xdata uint8_t ao_usb_ep0_in_len;
+__xdata uint8_t        ao_usb_ep0_in_buf[2];
+__xdata uint8_t ao_usb_ep0_out_len;
+__xdata uint8_t *__data ao_usb_ep0_out_data;
+__xdata uint8_t ao_usb_configuration;
+
+/* Send an IN data packet */
+static void
+ao_usb_ep0_flush(void)
+{
+       __xdata uint8_t this_len;
+       __xdata uint8_t cs0;
+
+       USBINDEX = 0;
+       cs0 = USBCS0;
+       if (cs0 & USBCS0_INPKT_RDY)
+               ao_panic(0);
+
+       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)
+{
+       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];
+       }
+}
+
+/* Read data from the ep0 OUT fifo
+ */
+static void
+ao_usb_ep0_fill(void)
+{
+       __xdata 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)
+{
+       __xdata 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;
+                       }
+               }
+       }
+}
+
+void
+ao_usb_flush(void) __critical
+{
+       if (ao_usb_in_bytes) {
+               USBINDEX = AO_USB_IN_EP;
+               USBCSIL |= USBCSIL_INPKT_RDY;
+               ao_usb_in_bytes = 0;
+       }
+}
+
+void
+ao_usb_putchar(char c) __critical
+{
+       if (!ao_usb_running)
+               return;
+       for (;;) {
+               USBINDEX = AO_USB_IN_EP;
+               if ((USBCSIL & USBCSIL_INPKT_RDY) == 0)
+                       break;
+               ao_sleep(&ao_usb_in_bytes);
+       }
+       USBFIFO[AO_USB_IN_EP << 1] = c;
+       if (++ao_usb_in_bytes == AO_USB_IN_SIZE) {
+               USBINDEX = AO_USB_IN_EP;
+               USBCSIL |= USBCSIL_INPKT_RDY;
+               ao_usb_in_bytes = 0;
+       }
+}
+
+char
+ao_usb_getchar(void) __critical
+{
+       __xdata char    c;
+       while (ao_usb_out_bytes == 0) {
+               for (;;) {
+                       USBINDEX = AO_USB_OUT_EP;
+                       if ((USBCSOL & USBCSOL_OUTPKT_RDY) != 0)
+                               break;
+                       ao_sleep(&ao_usb_out_bytes);
+               }
+               ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL;
+       }
+       --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;
+}
+
+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");
+}
diff --git a/src/ao_usb.h b/src/ao_usb.h
new file mode 100644 (file)
index 0000000..6633daf
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_USB_H_
+#define _AO_USB_H_
+
+#define AO_USB_SETUP_DIR_MASK  (0x01 << 7)
+#define AO_USB_SETUP_TYPE_MASK (0x03 << 5)
+#define AO_USB_SETUP_RECIP_MASK        (0x1f)
+
+#define AO_USB_DIR_OUT                 0
+#define AO_USB_DIR_IN                  (1 << 7)
+
+#define AO_USB_TYPE_STANDARD           0
+#define AO_USB_TYPE_CLASS              (1 << 5)
+#define AO_USB_TYPE_VENDOR             (2 << 5)
+#define AO_USB_TYPE_RESERVED           (3 << 5)
+
+#define AO_USB_RECIP_DEVICE            0
+#define AO_USB_RECIP_INTERFACE         1
+#define AO_USB_RECIP_ENDPOINT          2
+#define AO_USB_RECIP_OTHER             3
+
+/* standard requests */
+#define        AO_USB_REQ_GET_STATUS           0x00
+#define AO_USB_REQ_CLEAR_FEATURE       0x01
+#define AO_USB_REQ_SET_FEATURE         0x03
+#define AO_USB_REQ_SET_ADDRESS         0x05
+#define AO_USB_REQ_GET_DESCRIPTOR      0x06
+#define AO_USB_REQ_SET_DESCRIPTOR      0x07
+#define AO_USB_REQ_GET_CONFIGURATION   0x08
+#define AO_USB_REQ_SET_CONFIGURATION   0x09
+#define AO_USB_REQ_GET_INTERFACE       0x0A
+#define AO_USB_REQ_SET_INTERFACE       0x0B
+#define AO_USB_REQ_SYNCH_FRAME         0x0C
+
+#define AO_USB_DESC_DEVICE             1
+#define AO_USB_DESC_CONFIGURATION      2
+#define AO_USB_DESC_STRING             3
+#define AO_USB_DESC_INTERFACE          4
+#define AO_USB_DESC_ENDPOINT           5
+#define AO_USB_DESC_DEVICE_QUALIFIER   6
+#define AO_USB_DESC_OTHER_SPEED                7
+#define AO_USB_DESC_INTERFACE_POWER    8
+
+#define AO_USB_GET_DESC_TYPE(x)                (((x)>>8)&0xFF)
+#define AO_USB_GET_DESC_INDEX(x)       ((x)&0xFF)
+
+#define AO_USB_CONTROL_EP      0
+#define AO_USB_INT_EP          1
+#define AO_USB_OUT_EP          4
+#define AO_USB_IN_EP           5
+#define AO_USB_CONTROL_SIZE    32
+/*
+ * Double buffer IN and OUT EPs, so each
+ * gets half of the available space
+ *
+ * Ah, but USB bulk packets can only come in 8, 16, 32 and 64
+ * byte sizes, so we'll use 64 for everything
+ */
+#define AO_USB_IN_SIZE         64
+#define AO_USB_OUT_SIZE                64
+
+#define AO_USB_EP0_IDLE                0
+#define AO_USB_EP0_DATA_IN     1
+#define AO_USB_EP0_DATA_OUT    2
+
+#define LE_WORD(x)    ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8))
+
+/* CDC definitions */
+#define CS_INTERFACE      0x24
+#define CS_ENDPOINT       0x25
+
+#define SET_LINE_CODING         0x20
+#define GET_LINE_CODING         0x21
+#define SET_CONTROL_LINE_STATE  0x22
+
+/* Data structure for GET_LINE_CODING / SET_LINE_CODING class requests */
+struct ao_usb_line_coding {
+       uint32_t        rate;
+       uint8_t         char_format;
+       uint8_t         parity;
+       uint8_t         data_bits;
+} ;
+
+#endif /* _AO_USB_H_ */
diff --git a/src/cc1111.h b/src/cc1111.h
new file mode 100644 (file)
index 0000000..f55e802
--- /dev/null
@@ -0,0 +1,1214 @@
+/*-------------------------------------------------------------------------
+   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 */
+
+/* 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;
+
+/*
+ * 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_PRI1P1_TIMER1            (0 << 4)
+#define P2SEL_PRI1P1_TIMER4            (1 << 4)
+#define P2SEL_PRI0P1_USART0            (0 << 3)
+#define P2SEL_PRI0P1_TIMER1            (1 << 3)
+#define P2SEL_SELP2_4_GPIO             (0 << 2)
+#define P2SEL_SELP2_4_PERIPHERAL       (1 << 2)
+#define P2SEL_SELP2_3_GPIO             (0 << 1)
+#define P2SEL_SELP2_3_PERIPHERAL       (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;
+
+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)
+
+/* 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;
+sbit at 0xa5 P2_5;
+sbit at 0xa6 P2_6;
+sbit at 0xa7 P2_7;
+
+/* 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;
+
+/* 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 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
diff --git a/src/check-stack b/src/check-stack
new file mode 100755 (executable)
index 0000000..82680b8
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+HEADER=$1
+MEM=$2
+
+HEADER_STACK=`awk '/#define AO_STACK_START/ {print $3}' $HEADER | nickle`
+MEM_STACK=`awk '/Stack starts at/ {print $4}' $MEM | nickle`
+
+if [ "$HEADER_STACK" -lt "$MEM_STACK" ]; then
+       MIN=0x`nickle -e "$MEM_STACK # 16"`
+       echo "Set AO_STACK_START to at least $MIN"
+       exit 1
+else
+       exit 0
+fi
diff --git a/src/gps-cksum b/src/gps-cksum
new file mode 100755 (executable)
index 0000000..a08153b
--- /dev/null
@@ -0,0 +1,17 @@
+#!/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();
diff --git a/src/make-altitude b/src/make-altitude
new file mode 100644 (file)
index 0000000..ac04e84
--- /dev/null
@@ -0,0 +1,192 @@
+#!/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 count_to_kPa(real count)
+{
+       return (count / 2047 + 0.095) / 0.009;
+}
+
+for (real count = 0; count <= 2047; count++) {
+       real    kPa = count_to_kPa(count);
+       real    meters = pressure_to_altitude(kPa * 1000);
+       printf ("       %d,     /* %6.2g kPa %d count */\n",
+               floor (meters + 0.5), kPa, count);
+}
index eba587440684b807e7b7c0e3303c30c0b1bd67ae..1f7b6880b1ffcb4133811cc7ad7ed8b9ce3781c7 100644 (file)
@@ -427,7 +427,7 @@ adc_init(void)
        dma_config.cfg1 = (DMA_CFG1_SRCINC_0 |
                           DMA_CFG1_DESTINC_1 |
                           DMA_CFG1_PRIORITY_NORMAL);
-       
+
        dma_config.src_high = ADDRH(&ADCXDATA);
        dma_config.src_low = ADDRL(&ADCXDATA);
        dma_config.dst_high = ADDRH(adc_output);
@@ -442,7 +442,7 @@ adc_init(void)
                  (1 << 3) |    /* battery voltage */
                  (1 << 4) |    /* drogue sense */
                  (1 << 5));    /* main sense */
-       
+
        ADCCON1 = (ADCCON1_STSEL_START);        /* ST bit triggers */
        ADCCON2 = (ADCCON2_SREF_VDD |           /* reference voltage is VDD */
                   ADCCON2_SDIV_512 |           /* 12 bit ADC results */
@@ -554,7 +554,7 @@ main ()
        CLKCON = 0;
        while (!(SLEEP & SLEEP_XOSC_STB))
                ;
-       
+
        adc_init();
        P1_0 = 1;
        usart_init();
index bdc6c6149aa27f0503911c5742bf77b3d1bf42ea..3a63a2c6c191a2f20626fffa959faafcda73246f 100644 (file)
@@ -419,7 +419,7 @@ adc_init(void)
        dma_config.cfg1 = (DMA_CFG1_SRCINC_0 |
                           DMA_CFG1_DESTINC_1 |
                           DMA_CFG1_PRIORITY_NORMAL);
-       
+
        dma_config.src_high = ADDRH(&ADCXDATA);
        dma_config.src_low = ADDRL(&ADCXDATA);
        dma_config.dst_high = ADDRH(adc_output);
@@ -434,7 +434,7 @@ adc_init(void)
                  (1 << 3) |    /* battery voltage */
                  (1 << 4) |    /* drogue sense */
                  (1 << 5));    /* main sense */
-       
+
        ADCCON1 = (ADCCON1_STSEL_START);        /* ST bit triggers */
        ADCCON2 = (ADCCON2_SREF_VDD |           /* reference voltage is VDD */
                   ADCCON2_SDIV_512 |           /* 12 bit ADC results */
@@ -460,7 +460,7 @@ main ()
                ;
        while (P1 & 0x4)
                ;
-       
+
        adc_init();
        for (;;) {
                adc_run();
index 53b95495a657d607bc6cb87417b0f1b2dc57ad6a..b3fa8754206cf350f0c8e6680c67bc0bb27fc35e 100644 (file)
@@ -87,7 +87,7 @@ sfr at 0xCA T3CNT;
 sfr at 0xEA T4CNT;
 
 /* Timer control */
+
 sfr at 0xCB T3CTL;
 sfr at 0xEB T4CTL;
 
@@ -189,7 +189,7 @@ main ()
        T4CCTL0 = TxCCTLy_CMP_TOGGLE|TxCCTLy_CMP_MODE_ENABLE;
        T4CC0 = 125;
        T4CTL = TxCTL_DIV_32 | TxCTL_MODE_MODULO;
-       
+
        for (;;) {
                ___ _ ___ _ C ___ ___ _ ___ W   /* cq */
                ___ _ _ C _ W                   /* de */
index c35c39f6eefff930171fe33e583527270a5e2434..1762b65851f9041c357cc6438f7ea188c699d849 100644 (file)
@@ -322,7 +322,7 @@ dma_init(void)
        config.cfg1 = (DMA_CFG1_SRCINC_1 |
                       DMA_CFG1_DESTINC_1 |
                       DMA_CFG1_PRIORITY_NORMAL);
-       
+
        config.src_high = ADDRH(dma_input);
        config.src_low = ADDRL(dma_input);
        config.dst_high = ADDRH(dma_output);
@@ -351,7 +351,7 @@ main ()
        CLKCON = 0;
        while (!(SLEEP & SLEEP_XOSC_STB))
                ;
-       
+
        dma_init();
        dma_run();
        for (;;) {
index 7cc47120394a68ec54112826231fa5f58f588559..9ea22cdcc41fe74081e0a94c9ea0c10c22afe1df 100644 (file)
@@ -174,7 +174,7 @@ uint8_t
 bitbang_in_bit(void)
 {
        uint8_t b;
-       
+
        delay(1);
        SCK = 1;
        delay(1);
@@ -319,7 +319,7 @@ wrsr(uint8_t status)
        spi_out_byte(status);
        spi_cs(1);
 }
-       
+
 void
 wren(void)
 {
@@ -385,7 +385,7 @@ main ()
        CLKCON = 0;
        while (!(SLEEP & SLEEP_XOSC_STB))
                ;
-       
+
        spi_init();
 
        status = rdsr();
index 43aedc298838b4a8b2afd578c24ae9330d076627..ae4d04c5802f8eaf395f065d16b7f286638674e5 100644 (file)
@@ -87,4 +87,3 @@ void rf_isr (void) __interrupt(16) __using(1)
 void wdt_isr (void) __interrupt(17) __using(1)
 {
 }
-
index c9b3d1861d2c53045fe6dfb8e8ec6615a75fc744..ea7c984c1b17cf3d24e8fa706f34b4a198122784 100644 (file)
@@ -106,7 +106,7 @@ static __code uint8_t radio_setup[] = {
        RF_FREQ2_OFF,           FREQ_CONTROL >> 16,
        RF_FREQ1_OFF,           FREQ_CONTROL >> 8,
        RF_FREQ0_OFF,           FREQ_CONTROL >> 0,
-       
+
        RF_FSCTRL1_OFF,         (IF_FREQ_CONTROL << RF_FSCTRL1_FREQ_IF_SHIFT),
        RF_FSCTRL0_OFF,         (0 << RF_FSCTRL0_FREQOFF_SHIFT),
 
@@ -150,7 +150,7 @@ static __code uint8_t radio_setup[] = {
        /* default sync values */
        RF_SYNC1_OFF,           0xD3,
        RF_SYNC0_OFF,           0x91,
-       
+
        /* max packet length */
        RF_PKTLEN_OFF,          PACKET_LEN,
 
index 1f50d8a95721ca3eb6832a6384136db183ead36a..c50c32055e35b164756d570da52f69d86fdecf72 100644 (file)
@@ -46,7 +46,7 @@ main ()
                        packet[i] = RFD;
                }
                P1 = 0;
-               
+
                /* check packet contents */
                for (i = 0; i < PACKET_LEN; i++)
                        if (packet[i] != i)
index 2939042635ca84d48e0ea586d9fa6d518ea9d1cd..63f6c6de0c32ec477249f2cfb5db3c0995f509a6 100644 (file)
@@ -259,12 +259,12 @@ main ()
        CLKCON = 0;
        while (!(SLEEP & SLEEP_XOSC_STB))
                ;
-       
+
        usart_init();
 
        for (;;) {
                usart_out_string("hello world\r\n");
                debug_byte(usart_in_byte());
        }
-       
+
 }
index 7a531cc0a04e3ef080c00875079d7b96f36520a7..76c95c2747a18351160a19b7cb1721f072c193d2 100644 (file)
@@ -2,23 +2,23 @@
    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; either version 2 of the License, or
    (at your option) any later version.
-  
+
    This program is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.
-  
+
    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 
    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
@@ -135,37 +135,37 @@ sfr at 0xDD T1CC1H   ;  /*                                               */
 sfr at 0xDE T1CC2L   ;  /*                                               */
 sfr at 0xDF T1CC2H   ;  /*                                               */
 sfr at 0xE0 ACC      ;  /* ACCUMULATOR                                   */
-sfr at 0xE1 RFST     ;  /*                                               */ 
-sfr at 0xE2 T1CNTL   ;  /*                                               */ 
-sfr at 0xE3 T1CNTH   ;  /*                                               */ 
-sfr at 0xE4 T1CTL    ;  /*                                               */ 
-sfr at 0xE5 T1CCTL0  ;  /*                                               */ 
-sfr at 0xE6 T1CCTL1  ;  /*                                               */ 
-sfr at 0xE7 T1CCTL2  ;  /*                                               */ 
-sfr at 0xE8 IRCON2   ;  /*                                               */ 
-sfr at 0xE9 RFIF     ;  /*                                               */ 
-sfr at 0xEA T4CNT    ;  /*                                               */ 
-sfr at 0xEB T4CTL    ;  /*                                               */ 
-sfr at 0xEC T4CCTL0  ;  /*                                               */ 
-sfr at 0xED T4CC0    ;  /*                                               */ 
-sfr at 0xEE T4CCTL1  ;  /*                                               */ 
-sfr at 0xEF T4CC1    ;  /*                                               */ 
-sfr at 0xF0 B        ;  /*                                               */ 
-sfr at 0xF1 PERCFG   ;  /*                                               */ 
-sfr at 0xF2 ADCCFG   ;  /*                                               */ 
-sfr at 0xF3 P0SEL    ;  /*                                               */ 
-sfr at 0xF4 P1SEL    ;  /*                                               */ 
-sfr at 0xF5 P2SEL    ;  /*                                               */ 
-sfr at 0xF6 P1INP    ;  /*                                               */ 
-sfr at 0xF7 P2INP    ;  /*                                               */ 
-sfr at 0xF8 U1CSR    ;  /*                                               */ 
-sfr at 0xF9 U1DBUF   ;  /*                                               */ 
-sfr at 0xFA U1BAUD   ;  /*                                               */ 
-sfr at 0xFB U1UCR    ;  /*                                               */ 
-sfr at 0xFC U1GCR    ;  /*                                               */ 
-sfr at 0xFD P0DIR    ;  /*                                               */ 
-sfr at 0xFE P1DIR    ;  /*                                               */ 
-sfr at 0xFF P2DIR    ;  /*                                               */ 
+sfr at 0xE1 RFST     ;  /*                                               */
+sfr at 0xE2 T1CNTL   ;  /*                                               */
+sfr at 0xE3 T1CNTH   ;  /*                                               */
+sfr at 0xE4 T1CTL    ;  /*                                               */
+sfr at 0xE5 T1CCTL0  ;  /*                                               */
+sfr at 0xE6 T1CCTL1  ;  /*                                               */
+sfr at 0xE7 T1CCTL2  ;  /*                                               */
+sfr at 0xE8 IRCON2   ;  /*                                               */
+sfr at 0xE9 RFIF     ;  /*                                               */
+sfr at 0xEA T4CNT    ;  /*                                               */
+sfr at 0xEB T4CTL    ;  /*                                               */
+sfr at 0xEC T4CCTL0  ;  /*                                               */
+sfr at 0xED T4CC0    ;  /*                                               */
+sfr at 0xEE T4CCTL1  ;  /*                                               */
+sfr at 0xEF T4CC1    ;  /*                                               */
+sfr at 0xF0 B        ;  /*                                               */
+sfr at 0xF1 PERCFG   ;  /*                                               */
+sfr at 0xF2 ADCCFG   ;  /*                                               */
+sfr at 0xF3 P0SEL    ;  /*                                               */
+sfr at 0xF4 P1SEL    ;  /*                                               */
+sfr at 0xF5 P2SEL    ;  /*                                               */
+sfr at 0xF6 P1INP    ;  /*                                               */
+sfr at 0xF7 P2INP    ;  /*                                               */
+sfr at 0xF8 U1CSR    ;  /*                                               */
+sfr at 0xF9 U1DBUF   ;  /*                                               */
+sfr at 0xFA U1BAUD   ;  /*                                               */
+sfr at 0xFB U1UCR    ;  /*                                               */
+sfr at 0xFC U1GCR    ;  /*                                               */
+sfr at 0xFD P0DIR    ;  /*                                               */
+sfr at 0xFE P1DIR    ;  /*                                               */
+sfr at 0xFF P2DIR    ;  /*                                               */
 
 /*  BIT Registers  */
 
index fe25bfef77d4b36a23a19615bd30ca981396fb85..2b5ec02047bb2484bceb167f8ff7bc32d35a3244 100644 (file)
@@ -8,4 +8,3 @@ C D .
 . D .
 C D .
 . D R
-
index 1d4ff03d3a3f0ac210338bf1cedb24a767672ac8..3e67a2e0d5b586239332eb517059d6e243670ab7 100644 (file)
@@ -326,4 +326,3 @@ C - R
 . - R
 C - R
 . - R
-