UAVX Multicopter Flight Controller.

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
gke
Date:
Fri Feb 18 22:28:05 2011 +0000
Child:
1:1e3318a30ddd
Commit message:
First release

Changed in this revision

FATFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
Methods/sb_aux.cpp Show annotated file Show diff for this revision Revisions of this file
Methods/sb_getc.cpp Show annotated file Show diff for this revision Revisions of this file
Methods/sb_putc.cpp Show annotated file Show diff for this revision Revisions of this file
Methods/sb_uart0.cpp Show annotated file Show diff for this revision Revisions of this file
Methods/sb_uart1.cpp Show annotated file Show diff for this revision Revisions of this file
Methods/sb_uart2.cpp Show annotated file Show diff for this revision Revisions of this file
Methods/sb_uart3.cpp Show annotated file Show diff for this revision Revisions of this file
SDFileSystem/SDFileSystem.cpp Show annotated file Show diff for this revision Revisions of this file
SDFileSystem/SDFileSystem.h Show annotated file Show diff for this revision Revisions of this file
SerialBuffered.cpp Show annotated file Show diff for this revision Revisions of this file
SerialBuffered.h Show annotated file Show diff for this revision Revisions of this file
UAVXArm.c Show annotated file Show diff for this revision Revisions of this file
UAVXArm.h Show annotated file Show diff for this revision Revisions of this file
UAVXRevision.h Show annotated file Show diff for this revision Revisions of this file
accel.c Show annotated file Show diff for this revision Revisions of this file
analog.c Show annotated file Show diff for this revision Revisions of this file
attitude.c Show annotated file Show diff for this revision Revisions of this file
autonomous.c Show annotated file Show diff for this revision Revisions of this file
baro.c Show annotated file Show diff for this revision Revisions of this file
compass.c Show annotated file Show diff for this revision Revisions of this file
control.c Show annotated file Show diff for this revision Revisions of this file
gps.c Show annotated file Show diff for this revision Revisions of this file
gyro.c Show annotated file Show diff for this revision Revisions of this file
harness.c Show annotated file Show diff for this revision Revisions of this file
i2c.c Show annotated file Show diff for this revision Revisions of this file
ir.c Show annotated file Show diff for this revision Revisions of this file
irq.c Show annotated file Show diff for this revision Revisions of this file
leds.c Show annotated file Show diff for this revision Revisions of this file
math.c Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
menu.c Show annotated file Show diff for this revision Revisions of this file
nonvolatile.c Show annotated file Show diff for this revision Revisions of this file
outputs.c Show annotated file Show diff for this revision Revisions of this file
outputs_conventional.h Show annotated file Show diff for this revision Revisions of this file
outputs_copter.h Show annotated file Show diff for this revision Revisions of this file
outputs_y6.h Show annotated file Show diff for this revision Revisions of this file
params.c Show annotated file Show diff for this revision Revisions of this file
rc.c Show annotated file Show diff for this revision Revisions of this file
sb_globals.cpp Show annotated file Show diff for this revision Revisions of this file
sb_globals.h Show annotated file Show diff for this revision Revisions of this file
serial.c Show annotated file Show diff for this revision Revisions of this file
stats.c Show annotated file Show diff for this revision Revisions of this file
telemetry.c Show annotated file Show diff for this revision Revisions of this file
temperature.c Show annotated file Show diff for this revision Revisions of this file
uavx_aileron.h Show annotated file Show diff for this revision Revisions of this file
uavx_elevon.h Show annotated file Show diff for this revision Revisions of this file
uavx_helicopter.h Show annotated file Show diff for this revision Revisions of this file
uavx_multicopter.h Show annotated file Show diff for this revision Revisions of this file
utils.c Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FATFileSystem.lib	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_unsupported/code/fatfilesystem/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Methods/sb_aux.cpp	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,127 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+#include "../SerialBuffered.h"
+#include "../sb_globals.h"
+
+void SerialBuffered::format(int bits, int parity, int stopbits) {
+    SET_REGISTER(SERIALBUFFERED_LCR, (bits | parity | stopbits) & 0x7F);
+}
+
+void SerialBuffered::baud(int baud) {
+    uint16_t rate = calculate_baud(baud, uart_number);        
+    SET_REGISTER(SERIALBUFFERED_LCR, GET_REGISTER(SERIALBUFFERED_LCR) | 0x80);
+    SET_REGISTER(SERIALBUFFERED_DML, (rate >> 8) & 0xFF);
+    SET_REGISTER(SERIALBUFFERED_DLL, (rate &0xFF));
+    SET_REGISTER(SERIALBUFFERED_LCR, GET_REGISTER(SERIALBUFFERED_LCR) & 0x7F);
+}
+
+uint16_t SerialBuffered::calculate_baud(int baud, int uart) {
+    static int multipliers[4] = { 4, 1, 2, 8 };
+    int clock = 0;
+    
+    switch (uart) {
+        case 0: clock = (LPC_SC->PCLKSEL0 >>  6) & 0x3; break;
+        case 1: clock = (LPC_SC->PCLKSEL0 >>  8) & 0x3; break;
+        case 2: clock = (LPC_SC->PCLKSEL1 >> 16) & 0x3; break;
+        case 3: clock = (LPC_SC->PCLKSEL1 >> 18) & 0x3; break;
+    }
+    
+    return (uint16_t)(((SystemCoreClock / 16 / baud) * multipliers[clock]) & 0xFFFF);
+}
+
+void SerialBuffered::set_tx_buffer_size(int buffer_size, char *buffer) {
+    SET_REGISTER(SERIALBUFFERED_IER, GET_REGISTER(SERIALBUFFERED_IER) & (1UL << 2));
+    SET_REGISTER(SERIALBUFFERED_FCR, (1UL << 2) | 1);
+    _tx_buffer_size[uart_number] = buffer_size;
+    if (_tx_buffer_used_malloc[uart_number] && _tx_buffer[uart_number]) {
+        free(_tx_buffer[uart_number]);
+        _tx_buffer_used_malloc[uart_number] = false;
+    }
+    if (buffer == (char *)NULL) {
+        _tx_buffer[uart_number] = (char *)malloc(buffer_size);
+        _tx_buffer_used_malloc[uart_number] = true;
+    }
+    else {
+        _tx_buffer[uart_number] = buffer;
+        _tx_buffer_used_malloc[uart_number] = false;
+    }
+    _tx_buffer_in[uart_number] = _tx_buffer_out[uart_number] = 0;
+    _tx_buffer_full[uart_number] = false;
+    SET_REGISTER(SERIALBUFFERED_IER, GET_REGISTER(SERIALBUFFERED_IER) | 0x2);
+}
+
+void SerialBuffered::set_tx_buffer_size(int buffer_size) {
+    set_tx_buffer_size(buffer_size, (char *)NULL);
+}
+
+/**
+ */
+void SerialBuffered::set_rx_buffer_size(int buffer_size, char *buffer) {
+    SET_REGISTER(SERIALBUFFERED_IER, GET_REGISTER(SERIALBUFFERED_IER) & (1UL << 1));
+    SET_REGISTER(SERIALBUFFERED_FCR, (1UL << 1) | 1);
+    _rx_buffer_size[uart_number] = buffer_size;
+    if (_rx_buffer_used_malloc[uart_number] && _rx_buffer[uart_number]) {
+        free(_rx_buffer[uart_number]);
+        _rx_buffer_used_malloc[uart_number] = false;
+    }
+    if (buffer == (char *)NULL) {
+        _rx_buffer[uart_number] = (char *)malloc(buffer_size);
+        _rx_buffer_used_malloc[uart_number] = true;
+    }
+    else {
+        _rx_buffer[uart_number] = buffer;
+        _rx_buffer_used_malloc[uart_number] = false;
+    }
+    _rx_buffer_in[uart_number] = _rx_buffer_out[uart_number] = 0;
+    _rx_buffer_full[uart_number] = false;
+    SET_REGISTER(SERIALBUFFERED_IER, GET_REGISTER(SERIALBUFFERED_IER) | 0x1); 
+}
+
+void SerialBuffered::set_rx_buffer_size(int buffer_size) {
+    set_rx_buffer_size(buffer_size, (char *)NULL);
+}
+
+
+void SerialBuffered::reset_uart_tx(int uart_number) {
+    SET_REGISTER(SERIALBUFFERED_IER, GET_REGISTER(SERIALBUFFERED_IER) & (1UL << 1));
+    SET_REGISTER(SERIALBUFFERED_FCR, (1UL << 2) | 1);
+    if (_tx_buffer_used_malloc[uart_number] && _tx_buffer[uart_number]) {
+        free(_tx_buffer[uart_number]);
+        _tx_buffer[uart_number] = (char *)NULL;
+        _tx_buffer_used_malloc[uart_number] = false;
+    }
+    _tx_buffer_in[uart_number] = _tx_buffer_out[uart_number] = 0;
+    _tx_buffer_full[uart_number] = false;
+}
+
+void SerialBuffered::reset_uart_rx(int uart_number) {
+    SET_REGISTER(SERIALBUFFERED_IER, GET_REGISTER(SERIALBUFFERED_IER) & (1UL << 0));
+    SET_REGISTER(SERIALBUFFERED_FCR, (1UL << 1) | 1);    
+    if (_rx_buffer_used_malloc[uart_number] && _rx_buffer[uart_number]) {
+        free(_rx_buffer[uart_number]);
+        _rx_buffer[uart_number] = (char *)NULL;
+        _rx_buffer_used_malloc[uart_number] = false;
+    }
+    _rx_buffer_in[uart_number] = _rx_buffer_out[uart_number] = 0;
+    _rx_buffer_full[uart_number] = false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Methods/sb_getc.cpp	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,46 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+#include "../SerialBuffered.h"
+#include "../sb_globals.h"
+
+int SerialBuffered::getc(bool blocking) {
+    char c;
+    
+    if (blocking) while (_rx_buffer_out[uart_number] == _rx_buffer_in[uart_number] && !_rx_buffer_full[uart_number]) ; /* Blocks! */    
+    else if (_rx_buffer_in[uart_number] == _rx_buffer_out[uart_number] && !_rx_buffer_full[uart_number]) return -1;
+    
+    c = _rx_buffer[uart_number][_rx_buffer_out[uart_number]++];
+    if (_rx_buffer_out[uart_number] >= _rx_buffer_size[uart_number]) {
+        _rx_buffer_out[uart_number] = 0;
+    } 
+    if (_rx_buffer_full[uart_number]) _rx_buffer_full[uart_number] = false;     
+    return (int)c;   
+}
+
+char SerialBuffered::getc(void) {
+    return (char)getc(true);
+}
+
+int SerialBuffered::readable(void) {
+    return (_rx_buffer_full[uart_number] || _rx_buffer_overflow[uart_number] || _rx_buffer_in[uart_number] != _rx_buffer_out[uart_number]) ? 1 : 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Methods/sb_putc.cpp	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,56 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+#include "../SerialBuffered.h"
+#include "../sb_globals.h"
+
+int SerialBuffered::putc(int c, bool blocking) {
+    if ((GET_REGISTER(SERIALBUFFERED_LSR) & 0x20) && (_tx_buffer_in[uart_number] == _tx_buffer_out[uart_number] && !_tx_buffer_full[uart_number])) {
+        SET_REGISTER(SERIALBUFFERED_THR, (uint8_t)c);
+    }
+    else {
+        if (_tx_buffer_full[uart_number]) {
+            if (blocking) while (_tx_buffer_full[uart_number]) ; /* Blocks!!! */    
+            else {
+                _tx_buffer_overflow[uart_number] = true;
+                return -1;
+            }
+        }  
+        _tx_buffer[uart_number][_tx_buffer_in[uart_number]++] = (char)c;
+        if (_tx_buffer_in[uart_number] >= _tx_buffer_size[uart_number]) {
+            _tx_buffer_in[uart_number] = 0;
+        }
+        if (_tx_buffer_in[uart_number] == _tx_buffer_out[uart_number] && !_tx_buffer_full[uart_number]) _tx_buffer_full[uart_number] = true;
+        SET_REGISTER(SERIALBUFFERED_IER, 0x3);        
+    }
+    return 0;
+}
+
+/** putc
+ */
+int SerialBuffered::putc(int c) {
+    return putc(c, true);
+}
+
+int SerialBuffered::writeable(void) {
+    return (!_tx_buffer_full[uart_number] && !_tx_buffer_overflow[uart_number]) ? 1 : 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Methods/sb_uart0.cpp	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,63 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+#include "../SerialBuffered.h"
+#include "../sb_globals.h"
+
+extern "C" void SerialBuffered_ISR(unsigned long, int);
+
+extern "C" static void SerialBuffered_ISR_0(void) __irq { SerialBuffered_ISR(LPC_UART0_BASE, 0); }
+
+void SerialBuffered::set_uart0(PinName tx, PinName rx) {
+    unsigned ier = 0;
+    
+    if (tx == NC && rx == NC) return; // Eh, why would one?
+    
+    LPC_SC->PCONP       |=  (1UL << 3);
+    LPC_SC->PCLKSEL0    &= ~(3UL << 6);
+    LPC_SC->PCLKSEL0    |=  (1UL << 6);
+    
+    if (tx == USBTX) { 
+        set_tx_buffer_size(SERIALBUFFERED_BUFFER_SIZE); 
+        LPC_PINCON->PINSEL0 &= ~(1UL << 4); 
+        LPC_PINCON->PINSEL0 |=  (1UL << 4); 
+        ier |= 1;
+    }
+    else { reset_uart_tx(0); }
+    
+    if (rx == USBRX) { 
+        set_rx_buffer_size(SERIALBUFFERED_BUFFER_SIZE); 
+        LPC_PINCON->PINSEL0 &= ~(1UL << 6); 
+        LPC_PINCON->PINSEL0 |=  (1UL << 6); 
+        ier |= 2;
+    }
+    else { reset_uart_rx(0); }
+    
+    if (ier) {
+        baud(9600);
+        format(SerialBuffered::WordLength8, SerialBuffered::NoParity, SerialBuffered::StopBit1);
+        LPC_UART0->FCR = 0x7;
+        NVIC_SetVector(UART0_IRQn, (uint32_t)SerialBuffered_ISR_0);
+        NVIC_EnableIRQ(UART0_IRQn);
+        LPC_UART0->IER = ier;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Methods/sb_uart1.cpp	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,75 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+#include "../SerialBuffered.h"
+#include "../sb_globals.h"
+
+extern "C" void SerialBuffered_ISR(unsigned long, int);
+
+extern "C" static void SerialBuffered_ISR_1(void) __irq { SerialBuffered_ISR(LPC_UART1_BASE, 1); }
+
+void SerialBuffered::set_uart1(PinName tx, PinName rx) {
+    unsigned ier = 0;
+    
+    if (tx == NC && rx == NC) return; // Eh, why would one?
+
+    LPC_SC->PCONP       |=  (1UL << 4);
+    LPC_SC->PCLKSEL0    &= ~(3UL << 8);
+    LPC_SC->PCLKSEL0    |=  (1UL << 8);
+    
+    if (rx == p14) { 
+        set_rx_buffer_size(SERIALBUFFERED_BUFFER_SIZE); 
+        LPC_PINCON->PINSEL1 &= ~(3UL << 0); 
+        LPC_PINCON->PINSEL1 |=  (1UL << 0); 
+        ier |= 1; 
+    }
+    else if (rx == p25) { 
+        set_rx_buffer_size(SERIALBUFFERED_BUFFER_SIZE); 
+        LPC_PINCON->PINSEL4 &= ~(3UL << 2); 
+        LPC_PINCON->PINSEL4 |=  (2UL << 2); 
+        ier |= 1; 
+    }
+    else { reset_uart_rx(1); }
+    
+    if (tx == p13) { 
+        set_tx_buffer_size(SERIALBUFFERED_BUFFER_SIZE); 
+        LPC_PINCON->PINSEL0 &= ~(3UL << 30); 
+        LPC_PINCON->PINSEL0 |= (1UL << 30); 
+        ier |= 2; 
+    }
+    else if (tx == p26) { 
+        set_tx_buffer_size(SERIALBUFFERED_BUFFER_SIZE); 
+        LPC_PINCON->PINSEL4 &= ~(3UL <<  0); 
+        LPC_PINCON->PINSEL4 |= (2UL <<  0); 
+        ier |= 2; 
+    }
+    else { reset_uart_tx(1); }
+    
+    if (ier) {
+        baud(9600);
+        format(SerialBuffered::WordLength8, SerialBuffered::NoParity, SerialBuffered::StopBit1);
+        LPC_UART1->FCR = 0x7;
+        NVIC_SetVector(UART1_IRQn, (uint32_t)SerialBuffered_ISR_1);
+        NVIC_EnableIRQ(UART1_IRQn);    
+        LPC_UART1->IER = ier;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Methods/sb_uart2.cpp	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,63 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+#include "../SerialBuffered.h"
+#include "../sb_globals.h"
+
+extern "C" void SerialBuffered_ISR(unsigned long, int);
+
+extern "C" static void SerialBuffered_ISR_2(void) __irq { SerialBuffered_ISR(LPC_UART2_BASE, 2); }
+
+void SerialBuffered::set_uart2(PinName tx, PinName rx) {
+    volatile char c __attribute__((unused));
+    unsigned ier = 0;
+
+    if (tx == NC && rx == NC) return; // Eh, why would one?
+
+    LPC_SC->PCONP       |=  (1UL << 24);
+    LPC_SC->PCLKSEL1    &= ~(3UL << 16);
+    LPC_SC->PCLKSEL1    |=  (1UL << 16);
+    if (rx == p27) { 
+        set_rx_buffer_size(SERIALBUFFERED_BUFFER_SIZE); 
+        LPC_PINCON->PINSEL0 &= ~(3UL << 22); 
+        LPC_PINCON->PINSEL0 |=  (1UL << 22); 
+        ier |= 1; 
+    }
+    else { reset_uart_rx(2); }
+    if (tx == p28) { 
+        set_tx_buffer_size(SERIALBUFFERED_BUFFER_SIZE); 
+        LPC_PINCON->PINSEL0 &= ~(3UL << 20); 
+        LPC_PINCON->PINSEL0 |= (1UL << 20); 
+        ier |= 2; 
+    }
+    else { reset_uart_tx(2); }
+    
+    if (ier) {
+        baud(9600);
+        format(SerialBuffered::WordLength8, SerialBuffered::NoParity, SerialBuffered::StopBit1);
+        LPC_UART2->FCR = 0x7;
+        NVIC_SetVector(UART2_IRQn, (uint32_t)SerialBuffered_ISR_2);
+        NVIC_EnableIRQ(UART2_IRQn);    
+        LPC_UART2->IER = ier;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Methods/sb_uart3.cpp	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,63 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+#include "../SerialBuffered.h"
+#include "../sb_globals.h"
+
+extern "C" void SerialBuffered_ISR(unsigned long, int);
+
+extern "C" static void SerialBuffered_ISR_3(void) __irq { SerialBuffered_ISR(LPC_UART3_BASE, 3); }
+
+void SerialBuffered::set_uart3(PinName tx, PinName rx) {
+    volatile char c __attribute__((unused));
+    unsigned ier = 0;
+
+    if (tx == NC && rx == NC) return; // Eh, why would one?
+    
+    LPC_SC->PCONP       |=  (1UL << 25);
+    LPC_SC->PCLKSEL1    &= ~(3UL << 18);
+    LPC_SC->PCLKSEL1    |=  (1UL << 18);
+    if (rx == p10) { 
+        set_rx_buffer_size(SERIALBUFFERED_BUFFER_SIZE); 
+        LPC_PINCON->PINSEL0 &= ~(3UL << 2); 
+        LPC_PINCON->PINSEL0 |= (2UL << 2); 
+        ier |= 1; 
+    }
+    else { reset_uart_rx(3); }
+    
+    if (tx == p9) { 
+        set_tx_buffer_size(SERIALBUFFERED_BUFFER_SIZE); 
+        LPC_PINCON->PINSEL0 &= ~(3UL << 0); 
+        LPC_PINCON->PINSEL0 |= (2UL << 0); 
+        ier |= 2; 
+    }
+    else { reset_uart_tx(3); }
+    
+    if (ier) {
+        baud(9600);
+        format(SerialBuffered::WordLength8, SerialBuffered::NoParity, SerialBuffered::StopBit1);
+        LPC_UART3->FCR = 0x7;
+        NVIC_SetVector(UART3_IRQn, (uint32_t)SerialBuffered_ISR_3);
+        NVIC_EnableIRQ(UART3_IRQn);
+        LPC_UART3->IER = ier;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem/SDFileSystem.cpp	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,457 @@
+/* mbed SDFileSystem Library, for providing file access to SD cards
+ * Copyright (c) 2008-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* Introduction
+ * ------------
+ * SD and MMC cards support a number of interfaces, but common to them all
+ * is one based on SPI. This is the one I'm implmenting because it means
+ * it is much more portable even though not so performant, and we already 
+ * have the mbed SPI Interface!
+ *
+ * The main reference I'm using is Chapter 7, "SPI Mode" of: 
+ *  http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
+ *
+ * SPI Startup
+ * -----------
+ * The SD card powers up in SD mode. The SPI interface mode is selected by
+ * asserting CS low and sending the reset command (CMD0). The card will 
+ * respond with a (R1) response.
+ *
+ * CMD8 is optionally sent to determine the voltage range supported, and 
+ * indirectly determine whether it is a version 1.x SD/non-SD card or 
+ * version 2.x. I'll just ignore this for now.
+ *
+ * ACMD41 is repeatedly issued to initialise the card, until "in idle"
+ * (bit 0) of the R1 response goes to '0', indicating it is initialised.
+ *
+ * You should also indicate whether the host supports High Capicity cards,
+ * and check whether the card is high capacity - i'll also ignore this
+ *
+ * SPI Protocol
+ * ------------
+ * The SD SPI protocol is based on transactions made up of 8-bit words, with
+ * the host starting every bus transaction by asserting the CS signal low. The
+ * card always responds to commands, data blocks and errors.
+ * 
+ * The protocol supports a CRC, but by default it is off (except for the 
+ * first reset CMD0, where the CRC can just be pre-calculated, and CMD8)
+ * I'll leave the CRC off I think! 
+ * 
+ * Standard capacity cards have variable data block sizes, whereas High 
+ * Capacity cards fix the size of data block to 512 bytes. I'll therefore
+ * just always use the Standard Capacity cards with a block size of 512 bytes.
+ * This is set with CMD16.
+ *
+ * You can read and write single blocks (CMD17, CMD25) or multiple blocks 
+ * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When
+ * the card gets a read command, it responds with a response token, and then 
+ * a data token or an error.
+ * 
+ * SPI Command Format
+ * ------------------
+ * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC.
+ *
+ * +---------------+------------+------------+-----------+----------+--------------+
+ * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 |
+ * +---------------+------------+------------+-----------+----------+--------------+
+ *
+ * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95)
+ *
+ * All Application Specific commands shall be preceded with APP_CMD (CMD55).
+ *
+ * SPI Response Format
+ * -------------------
+ * The main response format (R1) is a status byte (normally zero). Key flags:
+ *  idle - 1 if the card is in an idle state/initialising 
+ *  cmd  - 1 if an illegal command code was detected
+ *
+ *    +-------------------------------------------------+
+ * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle |
+ *    +-------------------------------------------------+
+ *
+ * R1b is the same, except it is followed by a busy signal (zeros) until
+ * the first non-zero byte when it is ready again.
+ *
+ * Data Response Token
+ * -------------------
+ * Every data block written to the card is acknowledged by a byte 
+ * response token
+ *
+ * +----------------------+
+ * | xxx | 0 | status | 1 |
+ * +----------------------+
+ *              010 - OK!
+ *              101 - CRC Error
+ *              110 - Write Error
+ *
+ * Single Block Read and Write
+ * ---------------------------
+ *
+ * Block transfers have a byte header, followed by the data, followed
+ * by a 16-bit CRC. In our case, the data will always be 512 bytes.
+ *  
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ * | 0xFE | data[0] | data[1] |        | data[n] | crc[15:8] | crc[7:0] | 
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ */
+ 
+#include "SDFileSystem.h"
+
+#define SD_COMMAND_TIMEOUT 5000
+
+SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name) :
+  FATFileSystem(name), _spi(mosi, miso, sclk), _cs(cs) {
+      _cs = 1; 
+}
+
+#define R1_IDLE_STATE           (1 << 0)
+#define R1_ERASE_RESET          (1 << 1)
+#define R1_ILLEGAL_COMMAND      (1 << 2)
+#define R1_COM_CRC_ERROR        (1 << 3)
+#define R1_ERASE_SEQUENCE_ERROR (1 << 4)
+#define R1_ADDRESS_ERROR        (1 << 5)
+#define R1_PARAMETER_ERROR      (1 << 6)
+
+// Types
+//  - v1.x Standard Capacity
+//  - v2.x Standard Capacity
+//  - v2.x High Capacity
+//  - Not recognised as an SD Card
+
+#define SDCARD_FAIL 0
+#define SDCARD_V1   1
+#define SDCARD_V2   2
+#define SDCARD_V2HC 3
+
+int SDFileSystem::initialise_card() {
+    // Set to 100kHz for initialisation, and clock card with cs = 1
+    _spi.frequency(100000); 
+    _cs = 1;
+    for(int i=0; i<16; i++) {   
+        _spi.write(0xFF);
+    }
+
+    // send CMD0, should return with all zeros except IDLE STATE set (bit 0)
+    if(_cmd(0, 0) != R1_IDLE_STATE) { 
+        fprintf(stderr, "No disk, or could not put SD card in to SPI idle state\n");
+        return SDCARD_FAIL;
+    }
+
+    // send CMD8 to determine whther it is ver 2.x
+    int r = _cmd8();
+    if(r == R1_IDLE_STATE) {
+        return initialise_card_v2();
+    } else if(r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
+        return initialise_card_v1();
+    } else {
+        fprintf(stderr, "Not in idle state after sending CMD8 (not an SD card?)\n");
+        return SDCARD_FAIL;
+    }
+}
+
+int SDFileSystem::initialise_card_v1() {
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        _cmd(55, 0); 
+        if(_cmd(41, 0) == 0) { 
+            return SDCARD_V1;
+        }
+    }
+
+    fprintf(stderr, "Timeout waiting for v1.x card\n");
+    return SDCARD_FAIL;
+}
+
+int SDFileSystem::initialise_card_v2() {
+    
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        _cmd(55, 0); 
+        if(_cmd(41, 0) == 0) { 
+            _cmd58();
+            return SDCARD_V2;
+        }
+    }
+
+    fprintf(stderr, "Timeout waiting for v2.x card\n");
+    return SDCARD_FAIL;
+}
+
+int SDFileSystem::disk_initialize() {
+
+    int i = initialise_card();
+//    printf("init card = %d\n", i);
+//    printf("OK\n");
+
+    _sectors = _sd_sectors();
+
+    // Set block length to 512 (CMD16)
+    if(_cmd(16, 512) != 0) {
+        fprintf(stderr, "Set 512-byte block timed out\n");
+        return 1;
+    }
+        
+    _spi.frequency(1000000); // Set to 1MHz for data transfer
+    return 0;
+}
+
+int SDFileSystem::disk_write(const char *buffer, int block_number) {
+    // set write address for single block (CMD24)
+    if(_cmd(24, block_number * 512) != 0) {
+        return 1;
+    }
+
+    // send the data block
+    _write(buffer, 512);    
+    return 0;    
+}
+
+int SDFileSystem::disk_read(char *buffer, int block_number) {        
+    // set read address for single block (CMD17)
+    if(_cmd(17, block_number * 512) != 0) {
+        return 1;
+    }
+    
+    // receive the data
+    _read(buffer, 512);
+    return 0;
+}
+
+int SDFileSystem::disk_status() { return 0; }
+int SDFileSystem::disk_sync() { return 0; }
+int SDFileSystem::disk_sectors() { return _sectors; }
+
+// PRIVATE FUNCTIONS
+
+int SDFileSystem::_cmd(int cmd, int arg) {
+    _cs = 0; 
+
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            _cs = 1;
+            _spi.write(0xFF);
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+int SDFileSystem::_cmdx(int cmd, int arg) {
+    _cs = 0; 
+
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+
+int SDFileSystem::_cmd58() {
+    _cs = 0; 
+    int arg = 0;
+    
+    // send a command
+    _spi.write(0x40 | 58);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            int ocr = _spi.write(0xFF) << 24;
+            ocr |= _spi.write(0xFF) << 16;
+            ocr |= _spi.write(0xFF) << 8;
+            ocr |= _spi.write(0xFF) << 0;
+//            printf("OCR = 0x%08X\n", ocr);
+            _cs = 1;
+            _spi.write(0xFF);
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+int SDFileSystem::_cmd8() {
+    _cs = 0; 
+    
+    // send a command
+    _spi.write(0x40 | 8); // CMD8
+    _spi.write(0x00);     // reserved
+    _spi.write(0x00);     // reserved
+    _spi.write(0x01);     // 3.3v
+    _spi.write(0xAA);     // check pattern
+    _spi.write(0x87);     // crc
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT * 1000; i++) {
+        char response[5];
+        response[0] = _spi.write(0xFF);
+        if(!(response[0] & 0x80)) {
+                for(int j=1; j<5; j++) {
+                    response[i] = _spi.write(0xFF);
+                }
+                _cs = 1;
+                _spi.write(0xFF);
+                return response[0];
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+int SDFileSystem::_read(char *buffer, int length) {
+    _cs = 0;
+
+    // read until start byte (0xFF)
+    while(_spi.write(0xFF) != 0xFE);
+
+    // read data
+    for(int i=0; i<length; i++) {
+        buffer[i] = _spi.write(0xFF);
+    }
+    _spi.write(0xFF); // checksum
+    _spi.write(0xFF);
+
+    _cs = 1;    
+    _spi.write(0xFF);
+    return 0;
+}
+
+int SDFileSystem::_write(const char *buffer, int length) {
+    _cs = 0;
+    
+    // indicate start of block
+    _spi.write(0xFE);
+    
+    // write the data
+    for(int i=0; i<length; i++) {
+        _spi.write(buffer[i]);
+    }
+    
+    // write the checksum
+    _spi.write(0xFF); 
+    _spi.write(0xFF);
+
+    // check the repsonse token
+    if((_spi.write(0xFF) & 0x1F) != 0x05) {
+        _cs = 1;
+        _spi.write(0xFF);        
+        return 1;
+    }
+
+    // wait for write to finish
+    while(_spi.write(0xFF) == 0);
+
+    _cs = 1; 
+    _spi.write(0xFF);
+    return 0;
+}
+
+static int ext_bits(char *data, int msb, int lsb) {
+    int bits = 0;
+    int size = 1 + msb - lsb; 
+    for(int i=0; i<size; i++) {
+        int position = lsb + i;
+        int byte = 15 - (position >> 3);
+        int bit = position & 0x7;
+        int value = (data[byte] >> bit) & 1;
+        bits |= value << i;
+    }
+    return bits;
+}
+
+int SDFileSystem::_sd_sectors() {
+
+    // CMD9, Response R2 (R1 byte + 16-byte block read)
+    if(_cmdx(9, 0) != 0) {
+        fprintf(stderr, "Didn't get a response from the disk\n");
+        return 0;
+    }
+    
+    char csd[16];    
+    if(_read(csd, 16) != 0) {
+        fprintf(stderr, "Couldn't read csd response from disk\n");
+        return 0;
+    }
+
+    // csd_structure : csd[127:126]
+    // c_size        : csd[73:62]
+    // c_size_mult   : csd[49:47]
+    // read_bl_len   : csd[83:80] - the *maximum* read block length
+
+    int csd_structure = ext_bits(csd, 127, 126);
+    int c_size = ext_bits(csd, 73, 62);
+    int c_size_mult = ext_bits(csd, 49, 47);
+    int read_bl_len = ext_bits(csd, 83, 80);
+
+//    printf("CSD_STRUCT = %d\n", csd_structure);
+    
+    if(csd_structure != 0) {
+        fprintf(stderr, "This disk tastes funny! I only know about type 0 CSD structures\n");
+        return 0;
+    }
+             
+    // memory capacity = BLOCKNR * BLOCK_LEN
+    // where
+    //  BLOCKNR = (C_SIZE+1) * MULT
+    //  MULT = 2^(C_SIZE_MULT+2) (C_SIZE_MULT < 8)
+    //  BLOCK_LEN = 2^READ_BL_LEN, (READ_BL_LEN < 12)         
+                            
+    int block_len = 1 << read_bl_len;
+    int mult = 1 << (c_size_mult + 2);
+    int blocknr = (c_size + 1) * mult;
+    int capacity = blocknr * block_len;
+        
+    int blocks = capacity / 512;
+        
+    return blocks;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem/SDFileSystem.h	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,83 @@
+/* mbed SDFileSystem Library, for providing file access to SD cards
+ * Copyright (c) 2008-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MBED_SDFILESYSTEM_H
+#define MBED_SDFILESYSTEM_H
+
+#include "mbed.h"
+#include "FATFileSystem.h"
+
+/** Access the filesystem on an SD Card using SPI
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "SDFileSystem.h"
+ *
+ * SDFileSystem sd(p5, p6, p7, p12, "sd"); // mosi, miso, sclk, cs
+ *  
+ * int main() {
+ *     FILE *fp = fopen("/sd/myfile.txt", "w");
+ *     fprintf(fp, "Hello World!\n");
+ *     fclose(fp);
+ * }
+ */
+class SDFileSystem : public FATFileSystem {
+public:
+
+    /** Create the File System for accessing an SD Card using SPI
+     *
+     * @param mosi SPI mosi pin connected to SD Card
+     * @param miso SPI miso pin conencted to SD Card
+     * @param sclk SPI sclk pin connected to SD Card
+     * @param cs   DigitalOut pin used as SD Card chip select
+     * @param name The name used to access the virtual filesystem
+     */
+    SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name);
+    virtual int disk_initialize();
+    virtual int disk_write(const char *buffer, int block_number);
+    virtual int disk_read(char *buffer, int block_number);    
+    virtual int disk_status();
+    virtual int disk_sync();
+    virtual int disk_sectors();
+
+    int initialise_card(); // unprotect to use to check for disk presence - gke
+ 
+protected:
+
+    int _cmd(int cmd, int arg);
+    int _cmdx(int cmd, int arg);
+    int _cmd8();
+    int _cmd58();
+    //   int initialise_card();
+    int initialise_card_v1();
+    int initialise_card_v2();
+    
+    int _read(char *buffer, int length);
+    int _write(const char *buffer, int length);
+    int _sd_sectors();
+    int _sectors;
+    
+    SPI _spi;
+    DigitalOut _cs;     
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SerialBuffered.cpp	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,123 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+
+#include "mbed.h"
+
+#ifndef SERIALBUFFERED_C
+#define SERIALBUFFERED_C
+#endif
+
+#include "SerialBuffered.h"
+#include "sb_globals.h"
+
+enum { None, One, Two };
+enum { WordLength5, WordLength6, WordLength7, WordLength8 };
+enum { NoParity, OddParity, EvenParity, Forced1, Forced0 };
+enum { StopBit1, StopBit2 };
+        
+SerialBuffered::SerialBuffered(PinName tx, PinName rx) : Serial(tx, rx) {
+
+    // Depending upon the pins used, set-up the Uart.
+    if (tx == p9 || rx == p10) {
+        uart_number = 3;
+        uart_base = LPC_UART3_BASE; 
+        set_uart3(tx, rx);
+    }
+    else if (tx == p13 || tx == p26 || rx == p14 || rx == p25) {        
+        uart_number = 1;
+        uart_base = LPC_UART1_BASE; 
+        set_uart1(tx, rx);
+    }
+    else if (tx == p28 || rx == p27) {
+        uart_number = 2;
+        uart_base = LPC_UART2_BASE; 
+        set_uart2(tx, rx);
+    }
+    else if (tx == USBTX || rx == USBRX) {
+        uart_number = 0;
+        uart_base = LPC_UART0_BASE; 
+        set_uart0(tx, rx);
+    }
+    else {
+        uart_number = -1;
+        return;
+    }
+}
+
+SerialBuffered::~SerialBuffered() {
+    if (_tx_buffer_used_malloc[uart_number] && _tx_buffer[uart_number]) free(_tx_buffer[uart_number]);
+    if (_rx_buffer_used_malloc[uart_number] && _rx_buffer[uart_number]) free(_rx_buffer[uart_number]);
+}
+        
+/** SerialBuffered_ISR
+ *
+ * The main Uart interrupt handler.
+ */
+extern "C" void SerialBuffered_ISR(unsigned long uart_base, int uart_number) {
+    char c __attribute__((unused));
+    volatile uint32_t iir, lsr;
+    
+    iir = GET_REGISTER(SERIALBUFFERED_IIR); 
+
+    if (iir & 1) {        
+        return;    /* Eh, wtf? */
+    }
+    
+    iir = (iir >> 1) & 0x3;   
+    
+    if (iir == 2) {
+        while(GET_REGISTER(SERIALBUFFERED_LSR) & 0x1) {
+            if (_rx_buffer_in[uart_number] == _rx_buffer_out[uart_number] && _rx_buffer_full[uart_number]) {            
+                c = GET_REGISTER(SERIALBUFFERED_RBR); /* Oh dear, we need a bigger buffer!, send to dev/null */
+                _rx_buffer_overflow[uart_number] = true;
+            }
+            else {
+                if (_rx_buffer[uart_number]) { /* Ensure buffer pointer is not null before use. */
+                    c = GET_REGISTER(SERIALBUFFERED_RBR);
+                    _rx_buffer[uart_number][_rx_buffer_in[uart_number]++] = c;
+                    if (_rx_buffer_in[uart_number] >= _rx_buffer_size[uart_number]) _rx_buffer_in[uart_number] = 0;
+                    if (_rx_buffer_in[uart_number] == _rx_buffer_out[uart_number]) _rx_buffer_full[uart_number] = true;
+                }
+            }
+        }
+    }
+    
+    if (iir == 1) {        
+        if (_tx_buffer[uart_number]) { /* Ensure buffer pointer is not null before use. */
+            if (_tx_buffer_in[uart_number] != _tx_buffer_out[uart_number] || _tx_buffer_full[uart_number]) {
+                SET_REGISTER(SERIALBUFFERED_THR, (uint32_t)(_tx_buffer[uart_number][_tx_buffer_out[uart_number]++]));
+                if (_tx_buffer_out[uart_number] >= _tx_buffer_size[uart_number]) _tx_buffer_out[uart_number] = 0;
+                _tx_buffer_full[uart_number] = false;            
+            }
+            else {
+                SET_REGISTER(SERIALBUFFERED_IER, 1);
+            }                
+        }
+    }
+    
+    if (iir == 3) {  
+        /* We need to provide an error handling system. For now, just dismiss the IRQ. */       
+        lsr = GET_REGISTER(SERIALBUFFERED_LSR);
+    } 
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SerialBuffered.h	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,303 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+#ifndef SERIALBUFFERED_H
+#define SERIALBUFFERED_H
+
+#include "mbed.h"
+
+
+
+/** SerialBuffered based on Serial but fully buffered IO
+ *
+ * Example:
+ * @code
+ * #include "mbed.h"
+ * #include "SerialBuffered.h"
+ *
+ * SerialBuffered serial1 (p13, p14); 
+ * SerialBuffered serial2 (p28, p27);
+ *
+ * int main() {
+ *     while(1) {
+ *         if (serial1.readable()) {
+ *             while (!serial2.writeable());
+ *             serial2.putc(serial1.getch());
+ *         }
+ *         if (serial2.readable()) {
+ *             while (!serial1.writeable());
+ *             serial1.putc(serial2.getc());
+ *         }
+ *     }
+ * }
+ * @endcode
+ *
+ * <b>Note</b>, because this system "traps" the interrupts for the UART
+ * being used <b>do not</b> use the .attach() method, otherwise the buffers
+ * will cease functioning. Or worse, behaviour becomes unpredictable.
+ */
+
+class SerialBuffered : public Serial {
+
+    public:
+        enum { None = 0, One = 1, Two = 2 };
+        enum { WordLength5 = 0, WordLength6 = 1, WordLength7 = 2, WordLength8 = 3 };
+        enum { NoParity = 0, OddParity = (1UL << 3), EvenParity = (3UL << 3), Forced1 = (5UL << 3), Forced0 = (7UL << 3) };
+        enum { StopBit1 = (0UL << 2), StopBit2 = (1UL << 2) };
+        
+        /** Create a SerialBuffered object connected to the specified pins
+         *
+         * @param PinName tx The Mbed TX pin for the uart port.
+         * @param PinName rx The Mbed RX pin for the uart port.
+         */
+        SerialBuffered(PinName tx, PinName rx);
+        
+        virtual ~SerialBuffered();
+        
+        /** Get a character from the serial stream.
+         *
+         * @return char A char value of the character read.
+         */
+        char getc(void);
+        
+        /** Gets a character from the serial stream with optional blocking.
+         *
+         * This method allows for getting a character from the serial stream
+         * if one is available. If <b>blocking</b> is true, the method will
+         * wait for serial input if the RX buffer is empty. If <b>blocking</b>
+         * is false, the method will return immediately if the RX buffer is empty.
+         * On return, if not blocking and the buffer was empty, -1 is returned.
+         *
+         * @param blocking true or false, when true will block.
+         * @return int An int representation of the 8bit char or -1 on buffer empty.
+         */
+        int  getc(bool blocking);
+        
+        /** Puts a characher to the serial stream.
+         *
+         * This sends a character out of the uart port or, if no room in the
+         * TX FIFO, will place the character into the TX buffer. <b>Note</b>, if the
+         * TX buffer is also full, this method will <b>block</b> (wait) until
+         * there is room in the buffer.
+         *
+         * @param int An int representation of the 8bit character to send.
+         * @return int Always returns zero.
+         */
+        int  putc(int c);
+        
+        /** Puts a characher to the serial stream.
+         *
+         * As with putc(int c) this function allows for a character to be sent
+         * to the uart TX port. However, an extra parameter is added to allow
+         * the caller to decide if the method should block or not. If blocking
+         * is disabled then this method returns -1 to signal there was no room 
+         * in the TX FIFO or the TX buffer. The character c passed is has not
+         * therefore been sent.
+         *
+         * @param int An int representation of the 8bit character to send.
+         * @param bool true if blocking required, false to disable blocking.
+         * @return int Zero on success, -1 if no room in TX FIFO or TX buffer.
+         */
+        int  putc(int c, bool blocking);
+        
+        /** Are there characters in the RX buffer we can read?
+         *
+         * @return int 1 if characters are available, 0 otherwise.
+         */
+        int  readable(void);
+        
+        /** Is there room in the TX buffer to send a character?
+         *
+         * @return int 1 if room available, 0 otherwise.
+         */
+        int  writeable(void);
+        
+        /** Set's the UART baud rate.
+         *
+         * Any allowed baudrate may be passed. However, you should
+         * ensure it matches the far end of the serial link.
+         * 
+         * @param int The baudrate to set.
+         */
+        void baud(int baudrate);
+        
+        /** Sets the serial format.
+         *
+         * Valid serial bit lengths are:-
+         * <ul>
+         *  <li>SerialBuffered::WordLength5</li>
+         *  <li>SerialBuffered::WordLength6</li>
+         *  <li>SerialBuffered::WordLength7</li>
+         *  <li>SerialBuffered::WordLength8</li>
+         * </ul>
+         *
+         * Valid serial parity are:-
+         * <ul>
+         *  <li>SerialBuffered::NoParity</li>
+         *  <li>SerialBuffered::OddParity</li>
+         *  <li>SerialBuffered::EvenParity</li>
+         *  <li>SerialBuffered::Forced1</li>
+         *  <li>SerialBuffered::Forced0</li>
+         * </ul>
+         *
+         * Valid stop bits are:-
+         * <ul>
+         *  <li>SerialBuffered::None</li>
+         *  <li>SerialBuffered::One</li>
+         *  <li>SerialBuffered::Two</li>
+         * </ul>
+         *
+         * @param int bits
+         * @param int parity
+         * @param int stopbits
+         */
+        void format(int bits, int parity, int stopbits);
+        
+        /** Change the TX buffer size
+         *
+         * By default, when the SerialBuffer object is created, a default
+         * TX buffer of 256 bytes in size is created. If you need a bigger
+         * (or smaller) buffer then use this function to change the TX buffer
+         * size. 
+         *
+         * <b>Note</b>, when a buffer is resized, any previous buffer
+         * in operation is discarded (destroyed and lost).
+         *
+         * @param int The size of the TX buffer required.
+         */
+        void set_tx_buffer_size(int buffer_size);
+        
+        /** Change the TX buffer size and provide your own allocation.
+         *
+         * This methos allows for the buffer size to be changed and for the
+         * caller to pass a pointer to an area of RAM they have already set
+         * aside to hold the buffer. The standard method is to malloc space
+         * from the heap. This method allows that to be overriden and use a
+         * user supplied buffer. 
+         *
+         * <b>Note</b>, the buffer you create must be of the size you specify!
+         * <b>Note</b>, when a buffer is resized, any previous buffer
+         * in operation is discarded (destroyed and lost).
+         *
+         * @param int The size of the TX buffer required.
+         * @param char* A pointer to a buffer area you previously allocated.
+         */
+        void set_tx_buffer_size(int buffer_size, char *buffer);
+        
+        /** Change the RX buffer size
+         *
+         * By default, when the SerialBuffer object is created, a default
+         * RX buffer of 256 bytes in size is created. If you need a bigger
+         * (or smaller) buffer then use this function to change the RX buffer
+         * size. 
+         *
+         * <b>Note</b>, when a buffer is resized, any previous buffer
+         * in operation is discarded (destroyed and lost).
+         *
+         * @param int The size of the RX buffer required.
+         */
+        void set_rx_buffer_size(int buffer_size);
+        
+        /** Change the RX buffer size and provide your own allocation.
+         *
+         * This methos allows for the buffer size to be changed and for the
+         * caller to pass a pointer to an area of RAM they have already set
+         * aside to hold the buffer. The standard method is to malloc space
+         * from the heap. This method allows that to be overriden and use a
+         * user supplied buffer. 
+         *
+         * <b>Note</b>, the buffer you create must be of the size you specify!
+         * <b>Note</b>, when a buffer is resized, any previous buffer
+         * in operation is discarded (destroyed and lost).
+         *
+         * @param int The size of the RX buffer required.
+         * @param char* A pointer to a buffer area you previously allocated.
+         */
+        void set_rx_buffer_size(int buffer_size, char *buffer);
+        
+    protected:
+        /** Calculate the divisors for a UART's baud
+         *
+         * @param int The desired baud rate
+         * @param int The UART in use to calculate for
+         */
+        uint16_t calculate_baud(int baud, int uart);
+            
+    private:
+        /** set_uart0
+         *
+         * Sets up the hardware and interrupts for the UART.
+         *
+         * @param PinName tx
+         * @param PinName rx
+         */
+        void set_uart0(PinName tx, PinName rx);
+        
+        /** set_uart1
+         *
+         * Sets up the hardware and interrupts for the UART.
+         *
+         * @param PinName tx
+         * @param PinName rx
+         */
+        void set_uart1(PinName tx, PinName rx);
+        
+        /** set_uart2
+         *
+         * Sets up the hardware and interrupts for the UART.
+         *
+         * @param PinName tx
+         * @param PinName rx
+         */
+        void set_uart2(PinName tx, PinName rx);
+        
+        /** set_uart3
+         *
+         * Sets up the hardware and interrupts for the UART.
+         *
+         * @param PinName tx
+         * @param PinName rx
+         */
+        void set_uart3(PinName tx, PinName rx);
+        
+        /** Reset the TX Buffer
+         *
+         * @param int The UART buffer to reset.
+         */
+        void reset_uart_tx(int uart_number);
+        
+        /** Reset the RX Buffer
+         *
+         * @param int The UART buffer to reset.
+         */
+        void reset_uart_rx(int uart_number);
+        
+        /** LPC1768 UART peripheral base address for UART in use.
+         */
+        unsigned long uart_base;
+        
+        /** LPC1768 UART number for UART in use.
+         */
+        int uart_number;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UAVXArm.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,192 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+volatile Flags     F;
+
+uint32 T1;
+
+boolean OK;
+uint8 ch;
+
+int main(void) {
+
+    InitMisc();
+    InitHarness();
+ 
+    InitRC();
+    InitTimersAndInterrupts();
+    GreenLED = 1;
+    InitLEDs();
+        
+    InitParameters();
+    ReadStatsPX();
+    InitMotors();
+    InitBattery();
+
+    LEDYellow_ON;
+    InitAccelerometers();
+    InitGyros();
+    InitIRSensors();
+    InitCompass();
+    InitRangefinder();
+
+    InitGPS();
+    InitNavigation();
+
+    InitTemperature();
+    InitBarometer();
+
+    ShowSetup(true);
+    
+    I2C0.frequency(MinI2CRate);
+
+    FirstPass = true;
+
+    while ( true ) {
+        StopMotors();
+
+        LightsAndSirens();    // Check for Rx signal, disarmed on power up, throttle closed, gyros ONLINE
+
+        State = Starting;
+        F.FirstArmed = false;
+
+        while ( Armed.read() ) { // no command processing while the Quadrocopter is armed
+
+            UpdateGPS();
+            if ( F.RCNewValues )
+                UpdateControls();
+
+            if ( ( F.Signal ) && ( FailState == MonitoringRx ) ) {
+                switch ( State  ) {
+                    case Starting:    // this state executed once only after arming
+
+                        LEDYellow_OFF;
+
+                        CreateLogfile();
+
+                        if ( !F.FirstArmed ) {
+                            mS[StartTime] = mSClock();
+                            F.FirstArmed = true;
+                        }
+
+                        InitControl();
+                        CaptureTrims();
+                        InitGPS();
+                        InitNavigation();
+
+                        DesiredThrottle = 0;
+                        ErectGyros(); // DO NOT MOVE AIRCRAFT!
+                        ZeroStats();
+                        DoStartingBeeps(3);
+                        
+                        SendParamPacket(0);
+                        SendParamPacket(1);
+
+                        mS[ArmedTimeout] = mSClock() + ARMED_TIMEOUT_MS;
+                        mS[RxFailsafeTimeout] = mSClock() + RC_NO_CHANGE_TIMEOUT_MS;
+                        F.ForceFailsafe = F.LostModel = false;
+
+                        State = Landed;
+                        break;
+                    case Landed:
+                        DesiredThrottle = 0;
+                        if ( mSClock() > mS[ArmedTimeout] )
+                            DoShutdown();
+                        else
+                            if ( StickThrottle < IdleThrottle ) {
+                                SetGPSOrigin();
+                                GetHeading();
+                                if ( F.NewCommands )
+                                    F.LostModel = F.ForceFailsafe;
+                            } else {
+#ifdef SIMULATE
+                                FakeBaroRelAltitude = 0;
+#endif // SIMULATE                        
+                                LEDPattern = 0;
+                                mS[NavActiveTime] = mSClock() + NAV_ACTIVE_DELAY_MS;
+                                Stats[RCGlitchesS] = RCGlitches; // start of flight
+                                SaveLEDs();
+                                if ( ParameterSanityCheck() )
+                                    State = InFlight;
+                                else
+                                    ALL_LEDS_ON;
+                            }
+                        break;
+                    case Landing:
+                        if ( StickThrottle > IdleThrottle ) {
+                            DesiredThrottle = 0;
+                            State = InFlight;
+                        } else
+                            if ( mSClock() < mS[ThrottleIdleTimeout] )
+                                DesiredThrottle = IdleThrottle;
+                            else {
+                                DesiredThrottle = 0; // to catch cycles between Rx updates
+                                F.MotorsArmed = false;
+                                Stats[RCGlitchesS] = RCGlitches - Stats[RCGlitchesS];
+                                WriteStatsPX();
+                                WritePXImagefile();
+                                mS[ArmedTimeout] = mSClock() + ARMED_TIMEOUT_MS;
+                                State = Landed;
+                            }
+                        break;
+                    case Shutdown:
+                        // wait until arming switch is cycled
+                        F.LostModel = true;
+                        DesiredRoll = DesiredPitch = DesiredYaw = DesiredThrottle = 0;
+                        StopMotors();
+                        break;
+                    case InFlight:
+                        F.MotorsArmed = true;
+                        DoNavigation();
+                        LEDChaser();
+
+                        DesiredThrottle = SlewLimit(DesiredThrottle, StickThrottle, 1);
+
+                        if ( StickThrottle < IdleThrottle ) {
+                            mS[ThrottleIdleTimeout] = mSClock() + THROTTLE_LOW_DELAY_MS;
+                            RestoreLEDs();
+                            State = Landing;
+                        }
+                        break;
+                } // Switch State
+                mS[FailsafeTimeout] = mSClock() + FAILSAFE_TIMEOUT_MS;
+                FailState = MonitoringRx;
+            } else
+                DoPPMFailsafe();
+
+            DoControl();
+
+            MixAndLimitMotors();
+            MixAndLimitCam();
+            OutSignals();
+// zzz??? need to do some minor scheduling here with housekeeping
+            GetTemperature();
+            GetBattery();
+            CheckAlarms();
+            CheckTelemetry();
+
+            SensorTrace();
+
+        } // flight while armed
+    }
+} // main
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UAVXArm.h	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,1683 @@
+
+// Commissioning defines
+
+#define I2C_MAX_RATE_HZ    400000
+
+#define PWM_UPDATE_HZ       200             // MUST BE LESS THAN OR EAUAL TO 450HZ
+
+#define MCP4725_ID          0xc8            // or 0xcc
+
+#define SUPPRESS_SDCARD                     // no logging to check if buffering backup is an issue
+
+//BMP occasional returns bad results - changes outside this rate are deemed sensor/buss errors
+#define BARO_SANITY_CHECK_MPS    10.0       // dm/S 20,40,60,80 or 100
+
+#define SIX_DOF        // effects acc and gyro addresses
+
+#define SOFTWARE_CAM_PWM
+    
+#define BATTERY_VOLTS_SCALE   57.85         // 51.8144    // Volts scaling for internal divider
+
+//#define DCM_YAW_COMP
+//#define DISABLE_EXTRAS
+
+#define USING_MBED
+
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "mbed.h"
+#include "SDFileSystem.h"
+#include "SerialBuffered.h" // used in preference to MODSERIAL
+
+// Additional Types
+typedef uint8_t uint8 ;
+typedef int8_t int8;
+typedef uint16_t uint16;
+typedef int16_t int16;
+typedef int32_t int24;
+typedef uint32_t uint24;
+typedef int32_t int32;
+typedef uint32_t uint32;
+typedef uint8_t boolean;
+typedef float real32;
+
+extern Timer timer;
+
+//________________________________________________________________________________________
+
+
+// Useful Constants
+#define NUL     0
+#define SOH     1
+#define EOT     4
+#define ACK     6
+#define HT      9
+#define LF      10
+#define CR      13
+#define NAK     21
+#define ESC     27
+#define true    1
+#define false   0
+
+#define PI              3.141592654
+#define HALFPI          (PI*0.5)
+#define QUARTERPI       (PI*0.25)
+#define SIXTHPI         (PI/6.0)
+#define TWOPI           (PI*2.0)
+#define RADDEG          (180.0/PI)
+#define MILLIANGLE      (180000.0/PI)
+#define DEGRAD          (PI/180.0)
+
+#define MILLIRAD        18
+#define CENTIRAD        2
+
+#define MAXINT32        0x7fffffff
+#define MAXINT16        0x7fff
+
+//#define BATCHMODE
+
+#ifndef BATCHMODE
+//#define RX6CH
+//#define EXPERIMENTAL
+//#define TESTING
+//#define RX6CH                     // 6ch Receivers
+//#define SIMULATE
+//#define VTCOPTER
+//#define Y6COPTER
+#define QUADROCOPTER
+//#define TRICOPTER
+//#define HELICOPTER
+//#define AILERON
+// #define ELEVON
+#endif // !BATCHMODE
+
+//________________________________________________________________________________________________
+
+#define USE_PPM_FAILSAFE
+
+// Airframe
+
+#if ( defined TRICOPTER | defined QUADROCOPTER | defined VTCOPTER | defined Y6COPTER )
+#define MULTICOPTER
+#endif
+
+#if ( defined HELICOPTER | defined AILERON | defined ELEVON )
+#if ( defined AILERON | defined ELEVON )
+#define NAV_WING
+#endif
+#endif
+
+#ifdef QUADROCOPTER
+#define AF_TYPE QuadAF
+#endif
+#ifdef TRICOPTER
+#define AF_TYPE TriAF
+#endif
+#ifdef VTCOPTER
+#define AF_TYPE VTAF
+#endif
+#ifdef Y6COPTER
+#define AF_TYPE Y6AF
+#endif
+#ifdef HELICOPTER
+#define AF_TYPE HeliAF
+#endif
+#ifdef ELEVON
+#define AF_TYPE ElevAF
+#endif
+#ifdef AILERON
+#define AF_TYPE AilAF
+#endif
+
+#define GPS_INC_GROUNDSPEED                     // GPS groundspeed is not used for flight but may be of interest
+
+// Timeouts and Update Intervals
+
+#define FAILSAFE_TIMEOUT_MS             1000L   // mS. hold last "good" settings and then restore flight or abort
+#define ABORT_TIMEOUT_GPS_MS            5000L   // mS. go to descend on position hold if GPS valid.
+#define ABORT_TIMEOUT_NO_GPS_MS         0L      // mS. go to descend on position hold if GPS valid.  
+#define ABORT_UPDATE_MS                 1000L   // mS. retry period for RC Signal and restore Pilot in Control
+#define ARMED_TIMEOUT_MS                150000L    // mS. automatic disarming if armed for this long and landed
+
+#define ALT_DESCENT_UPDATE_MS           1000L    // mS time between throttle reduction clicks in failsafe descent without baro
+
+#define RC_STICK_MOVEMENT                5L        // minimum to be recognised as a stick input change without triggering failsafe
+
+#define THROTTLE_LOW_DELAY_MS           1000L   // mS. that motor runs at idle after the throttle is closed
+#define THROTTLE_UPDATE_MS              3000L   // mS. constant throttle time for altitude hold
+
+#define NAV_ACTIVE_DELAY_MS             10000L  // mS. after throttle exceeds idle that Nav becomes active
+#define NAV_RTH_LAND_TIMEOUT_MS         10000L  // mS. Shutdown throttle if descent lasts too long
+
+#define UAVX_TEL_INTERVAL_MS            125L    // mS. emit an interleaved telemetry packet
+#define ARDU_TEL_INTERVAL_MS            200L    // mS. Ardustation
+#define UAVX_CONTROL_TEL_INTERVAL_MS    10L     // mS. flight control only
+#define CUSTOM_TEL_INTERVAL_MS          250L    // mS.
+#define UAVX_MIN_TEL_INTERVAL_MS        1000L    // mS. emit minimum FPV telemetry packet slow rate for example to FrSky
+
+#define GPS_TIMEOUT_MS                  2000L   // mS.
+
+#define ALT_UPDATE_HZ                   20L     // Hz based on 50mS update time for Baro 
+
+#ifdef MULTICOPTER
+//#define PWM_UPDATE_HZ                   450L    // PWM motor update rate must be <450 and >100
+#else
+#define PWM_UPDATE_HZ                   40L     // standard RC servo update rate
+#endif // MULTICOPTER
+
+// Accelerometers
+
+#define DAMP_HORIZ_LIMIT                3L      // equivalent stick units - no larger than 5
+#define DAMP_VERT_LIMIT_LOW             -5L     // maximum throttle reduction
+#define DAMP_VERT_LIMIT_HIGH            20L     // maximum throttle increase
+
+// Gyros
+
+#define ATTITUDE_FF_DIFF                (24.0/16.0)   // 0 - 32 max feedforward speeds up roll/pitch recovery on fast stick change
+
+#define ATTITUDE_ENABLE_DECAY                   // enables decay to zero angle when roll/pitch is not in fact zero!
+// unfortunately there seems to be a leak which cause the roll/pitch
+// to increase without the decay.
+
+#define ATTITUDE_SCALE                  0.5     // scaling of stick units for attitude angle control 
+
+// Enable "Dynamic mass" compensation Roll and/or Pitch
+// Normally disabled for pitch only
+//#define DISABLE_DYNAMIC_MASS_COMP_ROLL
+//#define DISABLE_DYNAMIC_MASS_COMP_PITCH
+
+// Altitude Hold
+
+
+#define ALT_HOLD_MAX_ROC_MPS            0.5      // Must be changing altitude at less than this for alt. hold to be detected
+
+// the range within which throttle adjustment is proportional to altitude error
+#define ALT_BAND_M                      5.0     // Metres
+
+#define LAND_M                          3.0     // Metres deemed to have landed when below this height
+
+#define ALT_MAX_THR_COMP                40L     // Stick units was 32
+
+#define ALT_INT_WINDUP_LIMIT            16L
+
+#define ALT_RF_ENABLE_M                 5.0   // altitude below which the rangefiner is selected as the altitude source
+#define ALT_RF_DISABLE_M                6.0    // altitude above which the rangefiner is deselected as the altitude source
+
+// Navigation
+
+#define NAV_ACQUIRE_BEEPER
+
+//#define ATTITUDE_NO_LIMITS                // full stick range is available otherwise it is scaled to Nav sensitivity
+
+#define NAV_RTH_LOCKOUT                 ((10.0*PI)/180.0)    // first number is degrees
+
+#define NAV_MAX_ROLL_PITCH              25L     // Rx stick units
+#define NAV_CONTROL_HEADROOM            10L     // at least this much stick control headroom above Nav control    
+#define NAV_DIFF_LIMIT                  24L     // Approx double NAV_INT_LIMIT
+#define NAV_INT_WINDUP_LIMIT            64L     // ???
+
+#define NAV_ENFORCE_ALTITUDE_CEILING            // limit all autonomous altitudes
+#define NAV_CEILING                     120L    // 400 feet
+#define NAV_MAX_NEUTRAL_RADIUS          3L      // Metres also minimum closing radius
+#define NAV_MAX_RADIUS                  99L     // Metres
+
+#ifdef NAV_WING
+#define NAV_PROXIMITY_RADIUS           20.0     // Metres if there are no WPs
+#define NAV_PROXIMITY_ALTITUDE         5.0      // Metres
+#else
+#define NAV_PROXIMITY_RADIUS           5.0      // Metres if there are no WPs
+#define NAV_PROXIMITY_ALTITUDE         3.0      // Metres
+#endif // NAV_WING
+
+// reads $GPGGA sentence - all others discarded
+
+#define GPS_MIN_SATELLITES              6       // preferably > 5 for 3D fix
+#define GPS_MIN_FIX                     1       // must be 1 or 2 
+#define GPS_ORIGIN_SENTENCES            30L     // Number of sentences needed to obtain reasonable Origin
+#define GPS_MIN_HDILUTE                 130L    // HDilute * 100
+
+#define NAV_SENS_THRESHOLD              40L     // Navigation disabled if Ch7 is less than this
+#define NAV_SENS_ALTHOLD_THRESHOLD      20L     // Altitude hold disabled if Ch7 is less than this
+#define NAV_SENS_6CH                    80L     // Low GPS gain for 6ch Rx
+
+#define NAV_YAW_LIMIT                   10L     // yaw slew rate for RTH
+#define NAV_MAX_TRIM                    20L     // max trim offset for altitude hold
+#define NAV_CORR_SLEW_LIMIT             1L      // *5L maximum change in roll or pitch correction per GPS update
+
+#define ATTITUDE_HOLD_LIMIT             8L      // dead zone for roll/pitch stick for position hold
+#define ATTITUDE_HOLD_RESET_INTERVAL    25L     // number of impulse cycles before GPS position is re-acquired
+
+//#define NAV_PPM_FAILSAFE_RTH                // PPM signal failure causes RTH with Signal sampled periodically
+
+// Throttle
+
+#define THROTTLE_MAX_CURRENT            40L     // Amps total current at full throttle for estimated mAH
+#define CURRENT_SENSOR_MAX              50L     // Amps range of current sensor - used for estimated consumption - no actual sensor yet.
+#define THROTTLE_CURRENT_SCALE          ((THROTTLE_MAX_CURRENT * 1024L)/(200L * CURRENT_SENSOR_MAX ))
+
+#define THROTTLE_SLEW_LIMIT             0       // limits the rate at which the throttle can change (=0 no slew limit, 5 OK)
+#define THROTTLE_MIDDLE                 10      // throttle stick dead zone for baro 
+#define THROTTLE_MIN_ALT_HOLD           75      // min throttle stick for altitude lock
+
+// RC
+
+#define RC_INIT_FRAMES                  32      // number of initial RC frames to allow filters to settle
+
+#define RC_MIN_WIDTH_US                 900
+#define RC_MAX_WIDTH_US                 2100
+
+#define RC_NO_CHANGE_TIMEOUT_MS         20000L        // mS.
+
+typedef union {
+    int16 i16;
+    uint16 u16;
+    struct {
+        uint8 b0;
+        uint8 b1;
+    };
+    struct {
+        int8 pad;
+        int8 i1;
+    };
+} i16u;
+
+typedef union {
+    int24 i24;
+    uint24 u24;
+    struct {
+        uint8 b0;
+        uint8 b1;
+        uint8 b2;
+    };
+    struct {
+        uint8 pad;
+        int16 i2_1;
+    };
+} i24u;
+
+typedef union {
+    int32 i32;
+    uint32 u32;
+    struct {
+        uint8 b0;
+        uint8 b1;
+        uint8 b2;
+        uint8 b3;
+    };
+    struct {
+        uint16 w0;
+        uint16 w1;
+    };
+    struct {
+        int16 pad;
+        int16 iw1;
+    };
+
+    struct {
+        uint8 padding;
+        int24 i3_1;
+    };
+} i32u;
+
+#define TX_BUFF_MASK    511
+#define RX_BUFF_MASK    511
+
+typedef struct { // PPM
+    uint8 Head;
+    int16 B[4][8];
+} int16x8x4Q;
+
+typedef struct { // Baro
+    uint8 Head, Tail;
+    int24 B[8];
+} int24x8Q;
+
+typedef struct { // GPS
+    uint8 Head, Tail;
+    int32 Lat[4], Lon[4];
+} int32x4Q;
+
+// Macros
+
+#define Sign(i)                 (((i)<0) ? -1 : 1)
+
+#define Max(i,j)                ((i<j) ? j : i)
+#define Min(i,j)                ((i<j) ? i : j )
+#define Decay1(i)               (((i) < 0) ? (i+1) : (((i) > 0) ? (i-1) : 0))
+#define Limit(i,l,u)            (((i) < l) ? l : (((i) > u) ? u : (i)))
+#define Sqr(v)                  ( v * v )
+
+// To speed up NMEA sentence processing
+// must have a positive argument
+#define ConvertDDegToMPi(d)     (((int32)d * 3574L)>>11)
+#define ConvertMPiToDDeg(d)     (((int32)d * 2048L)/3574L)
+
+#define ToPercent(n, m)         (((n)*100L)/m)
+
+// Simple filters using weighted averaging
+#define VerySoftFilter(O,N)     (SRS16((O)+(N)*3, 2))
+#define SoftFilter(O,N)         (SRS16((O)+(N), 1))
+#define MediumFilter(O,N)       (SRS16((O)*3+(N), 2))
+#define HardFilter(O,N)         (SRS16((O)*7+(N), 3))
+
+// Unsigned
+#define VerySoftFilterU(O,N)    (((O)+(N)*3+2)>>2)
+#define SoftFilterU(O,N)        (((O)+(N)+1)>>1)
+#define MediumFilterU(O,N)      (((O)*3+(N)+2)>>2)
+#define HardFilterU(O,N)        (((O)*7+(N)+4)>>3)
+
+#define NoFilter(O,N)           (N)
+
+#define DisableInterrupts       (INTCONbits.GIEH=0)
+#define EnableInterrupts        (INTCONbits.GIEH=1)
+#define InterruptsEnabled       (INTCONbits.GIEH)
+
+// PARAMS
+
+#define PARAMS_ADDR_PX      0         // code assumes zero!
+#define MAX_PARAMETERS      64        // parameters in PXPROM start at zero
+
+#define STATS_ADDR_PX       ( PARAMS_ADDR_PX + (MAX_PARAMETERS *2) )
+#define MAX_STATS           64
+
+// uses second Page of PXPROM
+#define NAV_ADDR_PX         256L
+// 0 - 8 not used
+
+#define NAV_NO_WP           (NAV_ADDR_PX + 9)
+#define NAV_PROX_ALT        (NAV_ADDR_PX + 10)
+#define NAV_PROX_RADIUS     (NAV_ADDR_PX + 11)
+#define NAV_ORIGIN_ALT      (NAV_ADDR_PX + 12)
+#define NAV_ORIGIN_LAT      (NAV_ADDR_PX + 14)
+#define NAV_ORIGIN_LON      (NAV_ADDR_PX + 18)
+#define NAV_RTH_ALT_HOLD    (NAV_ADDR_PX + 22)    // P[NavRTHAlt]
+#define NAV_WP_START        (NAV_ADDR_PX + 24)
+
+#define WAYPOINT_REC_SIZE    (4 + 4 + 2 + 1)      // Lat + Lon + Alt + Loiter
+#define NAV_MAX_WAYPOINTS    ((256 - 24 - 1)/WAYPOINT_REC_SIZE)
+
+//______________________________________________________________________________________________
+
+// main.c
+
+enum Directions {BF, LR, UD, Alt }; // x forward, y left and z down
+enum Angles { Pitch, Roll, Yaw };   // X, Y, Z
+
+#define FLAG_BYTES 10
+#define TELEMETRY_FLAG_BYTES 6
+typedef union {
+    uint8 AllFlags[FLAG_BYTES];
+    struct { // Order of these flags subject to change
+        uint8
+AltHoldEnabled:
+        1,
+AllowTurnToWP:
+        1,            // stick programmed
+GyroFailure:
+        1,
+LostModel:
+        1,
+NearLevel:
+        1,
+LowBatt:
+        1,
+GPSValid:
+        1,
+NavValid:
+        1,
+
+BaroFailure:
+        1,
+AccFailure:
+        1,
+CompassFailure:
+        1,
+GPSFailure:
+        1,
+AttitudeHold:
+        1,
+ThrottleMoving:
+        1,
+HoldingAlt:
+        1,
+Navigate:
+        1,
+
+ReturnHome:
+        1,
+WayPointAchieved:
+        1,
+WayPointCentred:
+        1,
+Unused2: // was UsingGPSAlt:
+        1,
+UsingRTHAutoDescend:
+        1,
+BaroAltitudeValid:
+        1,
+RangefinderAltitudeValid:
+        1,
+UsingRangefinderAlt:
+        1,
+
+        // internal flags not really useful externally
+
+AllowNavAltitudeHold:
+        1,    // stick programmed
+UsingPositionHoldLock:
+        1,
+Ch5Active:
+        1,
+Simulation:
+        1,
+AcquireNewPosition:
+        1,
+MotorsArmed:
+        1,
+NavigationActive:
+        1,
+ForceFailsafe:
+        1,
+
+Signal:
+        1,
+RCFrameOK:
+        1,
+ParametersValid:
+        1,
+RCNewValues:
+        1,
+NewCommands:
+        1,
+AccelerationsValid:
+        1,
+CompassValid:
+        1,
+CompassMissRead:
+        1,
+
+UsingPolarCoordinates:
+        1,
+UsingAngleControl:
+        1,
+GPSPacketReceived:
+        1,
+NavComputed:
+        1,
+AltitudeValid:
+        1,
+UsingSerialPPM:
+        1,
+UsingTxMode2:
+        1,
+UsingAltOrientation:
+        1,
+
+        // outside telemetry flags
+
+UsingTelemetry:
+        1,
+TxToBuffer:
+        1,
+NewBaroValue:
+        1,
+BeeperInUse:
+        1,
+RFInInches:
+        1,
+FirstArmed:
+
+        1,
+HaveGPRMC:
+        1,
+UsingPolar:
+        1,
+RTCValid:
+        1,
+SDCardValid:
+        1,
+PXImageStale:
+        1,
+UsingLEDDriver:
+        1,
+Using9DOF:
+        1,
+HaveBatterySensor:
+        1;
+    };
+} Flags;
+
+enum FlightStates { Starting, Landing, Landed, Shutdown, InFlight};
+extern volatile Flags F;
+extern int8 State;
+
+//______________________________________________________________________________________________
+
+// accel.c
+
+#define ACC_FREQ  50     // Hz must be less than 100Hz
+const real32 OneOnTwoPiAccF = ( 1.0 / ( TWOPI * ACC_FREQ ));
+
+enum AccelerometerTypes { LISLAcc, ADXL345Acc, AccUnknown };
+
+extern void ShowAccType(void);
+extern void ReadAccelerometers(void);
+extern void GetNeutralAccelerations(void);
+extern void GetAccelerations(void);
+extern void AccelerometerTest(void);
+extern void InitAccelerometers(void);
+
+// ADXL345 3-Axis Accelerometer
+
+#ifdef SIX_DOF
+#define ADXL345_ID         0xA6
+#else
+#define ADXL345_ID         0x53
+#endif // 6DOF
+
+#define ADXL345_W           ADXL345_ID
+
+extern const float GRAVITY_ADXL345;
+
+extern void ReadADXL345Acc(void);
+extern void InitADXL345Acc(void);
+extern boolean ADXL345AccActive(void);
+
+// LIS3LV02DG 3-Axis Accelerometer 400KHz
+
+extern const float GRAVITY_LISL;
+
+#define LISL_WHOAMI      0x0f
+#define LISL_OFFSET_X    0x16
+#define LISL_OFFSET_Y    0x17
+#define LISL_OFFSET_Z    0x18
+#define LISL_GAIN_X      0x19
+#define LISL_GAIN_Y      0x1A
+#define LISL_GAIN_Z      0x1B
+#define LISL_CTRLREG_1   0x20
+#define LISL_CTRLREG_2   0x21
+#define LISL_CTRLREG_3   0x22
+#define LISL_STATUS      0x27
+#define LISL_OUTX_L      0x28
+#define LISL_OUTX_H      0x29
+#define LISL_OUTY_L      0x2A
+#define LISL_OUTY_H      0x2B
+#define LISL_OUTZ_L      0x2C
+#define LISL_OUTZ_H      0x2D
+#define LISL_FF_CFG      0x30
+#define LISL_FF_SRC      0x31
+#define LISL_FF_ACK      0x32
+#define LISL_FF_THS_L    0x34
+#define LISL_FF_THS_H    0x35
+#define LISL_FF_DUR      0x36
+#define LISL_DD_CFG      0x38
+#define LISL_INCR_ADDR   0x40
+#define LISL_READ        0x80
+#define LISL_ID          0x3a
+
+extern void WriteLISL(uint8, uint8);
+extern void ReadLISLAcc(void);
+extern boolean LISLAccActive(void);
+
+// other accelerometers
+
+extern real32 Vel[3], Acc[3], AccNeutral[3];
+extern int16 NewAccNeutral[3];
+extern uint8 AccelerometerType;
+
+//______________________________________________________________________________________________
+
+// analog.c
+
+extern void GetBattery(void);
+extern void BatteryTest(void);
+extern void InitBattery(void);
+
+extern void GetRangefinderAltitude(void);
+extern void InitRangefinder(void);
+
+extern real32 BatteryVolts, BatteryCurrentADCEstimated, BatteryChargeUsedAH;
+extern real32 BatteryCharge, BatteryCurrent;
+extern real32 BatteryVoltsScale;
+
+extern real32 RangefinderAltitude;
+
+//______________________________________________________________________________________________
+
+// attitude.c
+
+enum AttitudeMethods { PremerlaniDCM,  MadgwickIMU,  MadgwickAHRS};
+
+extern void GetAttitude(void);
+extern void DoLegacyYawComp(void);
+extern void AttitudeTest(void);
+extern void InitAttitude(void);
+
+extern real32 dT, dTR;
+extern uint32 PrevDCMUpdate;
+extern uint8 AttitudeMethod;
+
+// DCM Premerlani
+
+extern void DCMNormalise(void);
+extern void DCMDriftCorrection(void);
+extern void AccAdjust(void);
+extern void DCMMotionCompensation(void);
+extern void DCMUpdate(void);
+extern void DCMEulerAngles(void);
+
+extern real32 RollPitchError[3];
+extern real32 AccV[3];
+extern real32 GyroV[3];
+extern real32 OmegaV[3];
+extern real32 OmegaP[3];
+extern real32 OmegaI[3];
+extern real32 Omega[3];
+extern real32 DCM[3][3];
+extern real32 U[3][3];
+extern real32 TempM[3][3];
+
+// IMU & AHRS S.O.H. Madgwick
+
+extern void IMUupdate(real32, real32, real32, real32, real32, real32);
+extern void AHRSupdate(real32, real32, real32, real32, real32, real32, real32, real32, real32);
+extern void EulerAngles(void);
+
+extern real32 q0, q1, q2, q3;    // quaternion elements representing the estimated orientation
+
+//______________________________________________________________________________________________
+
+// autonomous.c
+
+extern void DoShutdown(void);
+extern void FailsafeHoldPosition(void);
+extern void DoPolarOrientation(void);
+extern void Navigate(int32, int32);
+extern void SetDesiredAltitude(int16);
+extern void DoFailsafeLanding(void);
+extern void AcquireHoldPosition(void);
+extern void NavGainSchedule(int16);
+extern void DoNavigation(void);
+extern void FakeFlight(void);
+extern void DoPPMFailsafe(void);
+extern void WriteWayPointPX(uint8, int32, int32, int16, uint8);
+extern void UAVXNavCommand(void);
+extern void GetWayPointPX(int8);
+extern void InitNavigation(void);
+
+typedef struct {
+    int32 E, N;
+    int16 A;
+    uint8 L;
+} WayPoint;
+
+enum NavStates { HoldingStation, ReturningHome, AtHome, Descending, Touchdown, Navigating, Loitering};
+enum FailStates { MonitoringRx, Aborting, Terminating, Terminated };
+
+extern real32 NavCorr[3], NavCorrp[3];
+extern real32 NavE[3], NavEp[3], NavIntE[3];
+extern int16 NavYCorrLimit;
+
+extern int8 FailState;
+extern WayPoint WP;
+extern int8 CurrWP;
+extern int8 NoOfWayPoints;
+extern int16 WPAltitude;
+extern int32 WPLatitude, WPLongitude;
+
+extern real32 WayHeading;
+extern real32 NavPolarRadius, NavNeutralRadius, NavProximityRadius, NavProximityAltitude;
+
+extern int24 NavRTHTimeoutmS;
+extern int8 NavState;
+extern int16 NavSensitivity, RollPitchMax;
+extern int16 AltSum;
+
+extern int16 EffNavSensitivity;
+extern int16 EastP, EastDiffSum, EastI, EastCorr, NorthP, NorthDiffSum, NorthI, NorthCorr;
+extern int24 EastD, EastDiffP, NorthD, NorthDiffP;
+
+//______________________________________________________________________________________________
+
+// baro.c
+
+#define BARO_INIT_RETRIES    10    // max number of initialisation retries
+
+enum BaroTypes { BaroBMP085, BaroSMD500, BaroMPX4115, BaroUnknown };
+
+#define ADS7823_TIME_MS     50      // 20Hz
+#define ADS7823_MAX         4095    // 12 bits
+#define ADS7823_ID          0x90    // ADS7823 ADC
+#define ADS7823_WR          0x90    // ADS7823 ADC
+#define ADS7823_RD          0x91    // ADS7823 ADC
+#define ADS7823_CMD         0x00
+
+#define MCP4725_MAX         4095    // 12 bits
+//#define MCP4725_ID          0xC8
+#define MCP4725_WR          MCP4725_ID
+#define MCP4725_RD          (MCP4725_ID+1)
+#define MCP4725_CMD         0x40    // write to DAC registor in next 2 bytes
+#define MCP4725_EPROM       0x60    // write to DAC registor and eprom
+
+extern void SetFreescaleMCP4725(int16);
+extern void SetFreescaleOffset(void);
+extern void ReadFreescaleBaro(void);
+extern real32 FreescaleToDM(int24);
+extern void GetFreescaleBaroAltitude(void);
+extern boolean IsFreescaleBaroActive(void);
+extern void InitFreescaleBarometer(void);
+
+#define BOSCH_ID_BMP085         0x55
+#define BOSCH_ID                0xee
+#define BOSCH_TEMP_BMP085       0x2e
+#define BOSCH_TEMP_SMD500       0x6e
+#define BOSCH_PRESS             0xf4
+#define BOSCH_CTL               0xf4                // OSRS=3 for BMP085 25.5mS, SMD500 34mS                
+#define BOSCH_ADC_MSB           0xf6
+#define BOSCH_ADC_LSB           0xf7
+#define BOSCH_ADC_XLSB          0xf8                // BMP085
+#define BOSCH_TYPE              0xd0
+
+extern void StartBoschBaroADC(boolean);
+extern void ReadBoschBaro(void);
+extern int24 CompensatedBoschPressure(uint16, uint16);
+extern void GetBoschBaroAltitude(void);
+extern boolean IsBoschBaroActive(void);
+extern void InitBoschBarometer(void);
+
+extern void GetBaroAltitude(void);
+extern void InitBarometer(void);
+
+extern void ShowBaroType(void);
+extern void BaroTest(void);
+
+extern int32 OriginBaroPressure, CompBaroPressure;
+extern uint16 BaroPressure, BaroTemperature;
+extern boolean AcquiringPressure;
+extern real32 BaroRelAltitude, BaroRelAltitudeP;
+extern i16u BaroVal;
+extern int8 BaroType;
+extern int16 AltitudeUpdateRate;
+extern int8 BaroRetries;
+
+extern real32 FakeBaroRelAltitude;
+
+//______________________________________________________________________________________________
+
+// compass.c
+
+enum CompassTypes { HMC5843, HMC6352, NoCompass };
+
+#define COMPASS_UPDATE_MS               50
+#define COMPASS_UPDATE_S                (real32)(COMPASS_UPDATE_MS * 0.001)
+#define COMPASS_FREQ                    10      // Hz must be less than 10Hz
+
+#define COMPASS_MAXDEV                30        // maximum yaw compensation of compass heading 
+#define COMPASS_MIDDLE                10        // yaw stick neutral dead zone
+
+const real32 OneOnTwoPiCompassF = ( 1.0 / ( TWOPI * COMPASS_FREQ ));
+
+extern void ReadCompass(void);
+extern void GetHeading(void);
+extern void ShowCompassType(void);
+extern void DoCompassTest(void);
+extern void CalibrateCompass(void);
+extern void InitCompass(void);
+
+// HMC5843 Compass
+
+#define HMC5843_ID      0x3C        // 0x1E 9DOF
+
+extern void ReadHMC5843(void);
+extern void GetHMC5843Parameters(void);
+extern void DoHMC5843Test(void);
+extern void CalibrateHMC5843(void);
+extern void InitHMC5843(void);
+extern boolean IsHMC5843Active(void);
+
+// HMC6352
+
+#define HMC6352_ID             0x42
+
+extern void ReadHMC6352(void);
+extern uint8 WriteByteHMC6352(uint8);
+extern void GetHMC6352Parameters(void);
+extern void DoHMC6352Test(void);
+extern void CalibrateHMC6352(void);
+extern void InitHMC6352(void);
+extern boolean HMC6352Active(void);
+
+typedef struct { real32 V; real32 Offset; } MagStruct;
+extern MagStruct Mag[3];
+extern real32 MagDeviation, CompassOffset;
+extern real32 MagHeading, Heading, FakeHeading;
+extern real32 HeadingSin, HeadingCos;
+extern uint8 CompassType;
+
+//______________________________________________________________________________________________
+
+// control.c
+
+extern void DoAltitudeHold(void);
+extern void UpdateAltitudeSource(void);
+extern void AltitudeHold(void);
+
+extern void LimitYawSum(void);
+extern void InertialDamping(void);
+extern void DoOrientationTransform(void);
+extern void DoControl(void);
+
+extern void LightsAndSirens(void);
+extern void InitControl(void);
+
+extern real32 Angle[3], Anglep[3], Rate[3], Ratep[3];
+extern real32 Comp[4];
+extern real32 DescentComp;
+extern real32 Rl, Pl, Yl, Ylp;
+extern real32 GS;
+
+extern int16 HoldYaw, YawSlewLimit;
+extern int16 CruiseThrottle, MaxCruiseThrottle, DesiredThrottle, IdleThrottle, InitialThrottle, StickThrottle;
+extern int16 DesiredRoll, DesiredPitch, DesiredYaw, DesiredHeading, DesiredCamPitchTrim;
+extern real32 ControlRoll, ControlPitch, ControlRollP, ControlPitchP;
+extern int16 CurrMaxRollPitch;
+
+extern int16 AttitudeHoldResetCount;
+extern real32 AltDiffSum, AltD, AltDSum;
+extern real32 DesiredAltitude, Altitude, AltitudeP;
+extern real32 ROC;
+extern boolean FirstPass;
+
+extern uint32 AltuSp;
+extern int16 DescentLimiter;
+
+extern int16 FakeDesiredPitch, FakeDesiredRoll, FakeDesiredYaw;
+
+//______________________________________________________________________________________________
+
+// gps.c
+
+extern void UpdateField(void);
+extern int32 ConvertGPSToM(int32);
+extern int32 ConvertMToGPS(int32);
+extern int24 ConvertInt(uint8, uint8);
+extern real32 ConvertReal(uint8, uint8);
+extern int32 ConvertLatLonM(uint8, uint8);
+extern void ConvertUTime(uint8, uint8);
+extern void ConvertUDate(uint8, uint8);
+extern void ParseGPGGASentence(void);
+extern void ParseGPRMCSentence(void);
+extern void SetGPSOrigin(void);
+extern void ParseGPSSentence(void);
+extern void RxGPSPacket(uint8);
+extern void SetGPSOrigin(void);
+extern void DoGPS(void);
+extern void GPSTest(void);
+extern void UpdateGPS(void);
+extern void InitGPS(void);
+
+#define MAXTAGINDEX         4
+#define GPSRXBUFFLENGTH     80
+typedef struct {
+    uint8 s[GPSRXBUFFLENGTH];
+    uint8 length;
+} NMEAStruct;
+
+#define MAX_NMEA_SENTENCES 2
+#define NMEA_TAG_INDEX 4
+
+enum GPSPackeType { GPGGAPacketTag, GPRMCPacketTag,  GPSUnknownPacketTag };
+extern NMEAStruct NMEA;
+extern const uint8 NMEATags[MAX_NMEA_SENTENCES][5];
+
+extern uint8 GPSPacketTag;
+extern tm GPSTime;
+extern int32 GPSStartTime, GPSSeconds;
+extern int32 GPSLatitude, GPSLongitude;
+extern int32 OriginLatitude, OriginLongitude;
+extern real32 GPSAltitude, GPSRelAltitude, GPSOriginAltitude;
+extern int32 DesiredLatitude, DesiredLongitude;
+extern int32 LatitudeP, LongitudeP, HoldLatitude, HoldLongitude;
+extern real32 GPSLongitudeCorrection;
+extern real32 GPSHeading, GPSMagHeading, GPSMagDeviation, GPSVel, GPSVelp, GPSROC;
+extern int8 GPSNoOfSats;
+extern int8 GPSFix;
+extern int16 GPSHDilute;
+
+extern real32 GPSdT, GPSdTR;
+extern uint32 GPSuSp;
+
+extern int32 FakeGPSLongitude, FakeGPSLatitude;
+
+extern uint8 ll, tt, ss, RxCh;
+extern uint8 GPSCheckSumChar, GPSTxCheckSum;
+
+//______________________________________________________________________________________________
+
+// gyro.c
+
+enum GyroTypes { MLX90609Gyro, ADXRS150Gyro, IDG300Gyro, LY530Gyro, ADXRS300Gyro, ITG3200Gyro,
+                 IRSensors, UnknownGyro
+               };
+
+extern void ReadGyros(void);
+extern void GetGyroRates(void);
+extern void CheckGyroFault(uint8, uint8, uint8);
+extern void ErectGyros(void);
+extern void GyroTest(void);
+extern void InitGyros(void);
+extern void ShowGyroType(void);
+
+// Generic Analog Gyrso
+extern void ReadAnalogGyros(void);
+extern void InitAnalogGyros(void);
+extern void CheckAnalogGyroFault(uint8, uint8, uint8);
+extern void AnalogGyroTest(void);
+
+// ITG3200 3 Axis Gyro
+
+#define ITG3200_WHO     0x00
+#define ITG3200_SMPL    0x15
+#define ITG3200_DLPF    0x16
+#define ITG3200_INT_C   0x17
+#define ITG3200_TMP_H   0x18
+#define ITG3200_TMP_L   0x1C
+#define ITG3200_GX_H    0x1D
+#define ITG3200_GX_L    0x1E
+#define ITG3200_GY_H    0x1F
+#define ITG3200_GY_L    0x20
+#define ITG3200_GZ_H    0x21
+#define ITG3200_GZ_L    0x22
+#define ITG3200_PWR_M   0x3E
+
+#ifdef SIX_DOF
+#define ITG3200_ID      0xD0
+#else
+#define ITG3200_ID      0xD2
+#endif // 6DOF
+
+#define ITG3200_R       (ITG3200_ID+1)
+#define ITG3200_W       ITG3200_ID
+
+extern void ReadITG3200Gyro(void);
+extern uint8 ReadByteITG3200(uint8);
+extern void WriteByteITG3200(uint8, uint8);
+extern void InitITG3200Gyro(void);
+extern void ITG3200Test(void);
+extern boolean ITG3200GyroActive(void);
+
+extern const real32 GyroToRadian[];
+extern real32 GyroADC[3], GyroNeutral[3], Gyro[3]; // Radians
+extern uint8 GyroType;
+
+//______________________________________________________________________________________________
+
+// harness.c
+
+
+extern void UpdateRTC(void);
+extern void InitHarness(void);
+
+extern LocalFileSystem Flash;
+
+// 1 GND
+// 2 4.5-9V
+// 3 VBat
+// 4 NReset
+
+//extern SPI SPI0;                  // 5 SPI MOSI, 6 SPI MOSO, 7 SPI CLK
+//extern DigitalOut SPICS;          // 8
+extern SDFileSystem SDCard;
+
+//extern I2C I2C1;                  // 9, 10
+extern SerialBuffered TelemetrySerial;
+extern DigitalIn Armed;             // 11 SPI MOSI
+extern DigitalOut PWMCamPitch;      // 12 SPI MOSO    // 12 SPI MOSO
+extern Serial GPSSerial;            // 13 Tx1 / SPI CLK, 14 Rx1
+
+extern AnalogIn PitchADC;           // 15 AN0
+extern AnalogIn RollADC;            // 16 AN1
+extern AnalogIn YawADC;             // 17 AN2
+
+extern AnalogIn RangefinderADC;     // 18 AN3
+extern AnalogIn BatteryCurrentADC;  // 19 AN4
+extern AnalogIn BatteryVoltsADC;    // 20 AN5
+
+extern PwmOut Out0;                 // 21
+extern PwmOut Out1;                 // 22
+extern PwmOut Out2;                 // 23
+extern PwmOut Out3;                 // 24
+
+//extern PwmOut Out4;                 // 25
+//extern PwmOut Out5;                 // 26
+extern DigitalOut DebugPin;                  // 25
+
+extern I2C I2C0;                    // 27, 28
+
+extern DigitalIn  RCIn;             // 29 CAN
+extern DigitalOut PWMCamRoll;      // 30 CAN
+
+//extern Serial TelemetrySerial;
+// 31 USB +, 32 USB -
+// 34 -37 Ethernet
+// 38 IF +
+// 39 IF -
+// 40 3.3V Out
+
+extern DigitalOut BlueLED;
+extern DigitalOut GreenLED;
+extern DigitalOut RedLED;
+extern DigitalOut YellowLED;
+
+extern InterruptIn RCInterrupt;
+
+extern char RTCString[], RTCLogfile[];
+extern struct tm* RTCTime;
+
+#define I2CTEMP I2C0
+#define I2CBARO I2C0
+#define I2CGYRO I2C0
+#define I2CACC I2C0
+#define I2CCOMPASS I2C0
+#define I2CESC I2C0
+#define I2CLED I2C0
+
+#define SPIACC SPI0
+
+#define mSClock timer.read_ms
+#define uSClock timer.read_us
+
+//______________________________________________________________________________________________
+
+// irq.c
+
+#define CONTROLS                7
+#define MAX_CONTROLS            12     // maximum Rx channels
+
+#define RxFilter            MediumFilterU
+//#define RxFilter            SoftFilterU
+//#define RxFilter            NoFilter
+
+#define RC_GOOD_BUCKET_MAX      20
+#define RC_GOOD_RATIO           4
+
+#define RC_MINIMUM              0
+
+#define RC_MAXIMUM              238
+
+#define RC_NEUTRAL              ((RC_MAXIMUM-RC_MINIMUM+1)/2)
+
+#define RC_MAX_ROLL_PITCH       (170)
+
+#define RC_THRES_STOP           ((6L*RC_MAXIMUM)/100)
+#define RC_THRES_START          ((10L*RC_MAXIMUM)/100)
+
+#define RC_FRAME_TIMEOUT_MS     25
+#define RC_SIGNAL_TIMEOUT_MS    (5L*RC_FRAME_TIMEOUT_MS)
+#define RC_THR_MAX              RC_MAXIMUM
+
+#define MAX_ROLL_PITCH          RC_NEUTRAL    // Rx stick units - rely on Tx Rate/Exp
+
+#ifdef RX6CH
+#define RC_CONTROLS 5
+#else
+#define RC_CONTROLS CONTROLS
+#endif //RX6CH
+
+extern void InitTimersAndInterrupts(void);
+
+extern void enableTxIrq0(void);
+extern void disableTxIrq0(void);
+extern void enableTxIrq1(void);
+extern void disableTxIrq1(void);
+
+extern void RCISR(void);
+extern void RCNullISR(void);
+extern void RCTimeoutISR(void);
+extern void GPSInISR(void);
+extern void GPSOutISR(void);
+extern void TelemetryInISR(void);
+extern void TelemetryOutISR(void);
+extern void RazorInISR(void);
+extern void RazorOutISR(void);
+
+enum { Clock, GeneralCountdown, UpdateTimeout, RCSignalTimeout, BeeperTimeout, ThrottleIdleTimeout,
+       FailsafeTimeout, AbortTimeout, RxFailsafeTimeout, DescentUpdate, StickChangeUpdate, NavStateTimeout, LastValidRx,
+       LastGPS, StartTime, GPSTimeout, LEDChaserUpdate, LastBattery, TelemetryUpdate, NavActiveTime, BeeperUpdate,
+       ArmedTimeout, ThrottleUpdate, RazorUpdate, VerticalDampingUpdate, CamUpdate, BaroUpdate, CompassUpdate
+     };
+
+enum WaitPacketStates { WaitSentinel, WaitTag, WaitBody, WaitCheckSum};
+
+extern uint32 mS[];
+extern int16 PPM[];
+extern int8 PPM_Index;
+extern uint32 PrevEdge, CurrEdge;
+extern uint8 Intersection, PrevPattern, CurrPattern;
+extern uint32 Width;
+extern uint8 RxState;
+extern boolean WaitingForSync;
+
+extern int8 SignalCount;
+extern uint16 RCGlitches;
+
+//______________________________________________________________________________________________
+
+// ir.c
+
+extern void GetIRAttitude(void);
+extern void TrackIRMaxMin(uint8);
+extern void InitIRSensors(void);
+
+extern real32 IR[3], IRMax, IRMin, IRSwing;
+
+//______________________________________________________________________________________________
+
+// i2c.c
+
+#define I2C_ACK  1
+#define I2C_NACK 0
+
+extern void TrackMinI2CRate(uint32);
+extern void ShowI2CDeviceName(uint8);
+extern uint8 ScanI2CBus(void);
+extern boolean ESCWaitClkHi(void);
+extern void ProgramSlaveAddress(uint8);
+extern void ConfigureESCs(void);
+
+extern uint32 MinI2CRate;
+
+//______________________________________________________________________________________________
+
+// leds.c
+
+#define PCA9551_ID         0xc0
+
+#define DRV0M              0x0001
+#define DRV1M              0x0002
+#define DRV2M              0x0004
+#define DRV3M              0x0008
+
+#define AUX0M              0x0010
+#define AUX1M              0x0020
+#define AUX2M              0x0040
+#define AUX3M              0x0080
+
+#define BeeperM            DRV0M
+
+#define YellowM            0x0100
+#define RedM               0x0200
+#define GreenM             0x0400
+#define BlueM              0x0800
+
+#define ALL_LEDS_ON        LEDsOn(BlueM|RedM|GreenM|YellowM)
+#define ALL_LEDS_OFF       LEDsOff(BlueM|RedM|GreenM|YellowM)
+
+#define AUX_LEDS_ON        LEDsOn(AUX0M|AUX1M|AUX2M|AUX3M)
+#define AUX_LEDS_OFF       LEDsOff(AUX0M|AUX1M|AUX2M|AUX3M)
+
+#define AUX_DRVS_ON        LEDsOn(DRV0M|DRV1M|DRV2M|DRV3M)
+#define AUX_DRVS_OFF       LEDsOff(DRV0M|DRV1M|DRV2M|DRV3M)
+
+#define ALL_LEDS_ARE_OFF   ( (LEDShadow&(BlueM|RedM|GreenM|YellowM))== (uint8)0 )
+
+#define BEEPER_IS_ON       ( (LEDShadow & BeeperM) != (uint8)0 )
+#define BEEPER_IS_OFF      ( (LEDShadow & BeeperM) == (uint8)0 )
+
+#define LEDRed_ON          LEDsOn(RedM)
+#define LEDBlue_ON         LEDsOn(BlueM)
+#define LEDGreen_ON        LEDsOn(GreenM)
+#define LEDYellow_ON       LEDsOn(YellowM)
+#define LEDAUX1_ON         LEDsOn(AUX1M)
+#define LEDAUX2_ON         LEDsOn(AUX2M)
+#define LEDAUX3_ON         LEDsOn(AUX3M)
+#define LEDRed_OFF         LEDsOff(RedM)
+#define LEDBlue_OFF        LEDsOff(BlueM)
+#define LEDGreen_OFF       LEDsOff(GreenM)
+#define LEDYellow_OFF      LEDsOff(YellowM)
+#define LEDYellow_TOG      if( (LEDShadow&YellowM) == (uint8)0 ) LEDsOn(YellowM); else LEDsOff(YellowM)
+#define LEDRed_TOG         if( (LEDShadow&RedM) == (uint8)0 ) LEDsOn(RedM); else LEDsOff(RedM)
+#define LEDBlue_TOG        if( (LEDShadow&BlueM) == (uint8)0 ) LEDsOn(BlueM); else LEDsOff(BlueM)
+#define LEDGreen_TOG       if( (LEDShadow&GreenM) == (uint8)0 ) LEDsOn(GreenM); else LEDsOff(GreenM)
+#define Beeper_OFF         LEDsOff(BeeperM)
+#define Beeper_ON          LEDsOn(BeeperM)
+#define Beeper_TOG         if( (LEDShadow&BeeperM) == (uint8)0 ) LEDsOn(BeeperM); else LEDsOff(BeeperM)
+
+extern void SendLEDs(void);
+extern void SaveLEDs(void);
+extern void RestoreLEDs(void);
+extern void LEDsOn(uint16);
+extern void LEDsOff(uint16);
+extern void LEDChaser(void);
+extern void DoLEDs(void);
+extern void PowerOutput(int8);
+extern void LEDsAndBuzzer(void);
+
+extern void PCA9551Test(void);
+extern void WritePCA9551(uint8);
+extern boolean IsPCA9551Active(void);
+
+extern void InitLEDs(void);
+
+extern uint16 LEDShadow, PrevLEDShadow, SavedLEDs, LEDPattern;
+extern uint8 PrevPCA9551LEDShadow;
+
+//______________________________________________________________________________________________
+
+// math.c
+
+extern int16 SRS16(int16, uint8);
+extern int32 SRS32(int32, uint8);
+extern real32 Make2Pi(real32);
+extern real32 MakePi(real32);
+extern int16 Table16(int16, const int16 *);
+
+extern real32 VDot(real32 v1[3], real32 v2[3]);
+extern void VCross(real32 VOut[3], real32 v1[3], real32 v2[3]);
+extern void VScale(real32 VOut[3], real32 v[3], real32 s);
+extern void VAdd(real32 VOut[3],real32 v1[3], real32 v2[3]);
+extern void VSub(real32 VOut[3],real32 v1[3], real32 v2[3]);
+
+//______________________________________________________________________________________________
+
+// menu.c
+
+extern void ShowPrompt(void);
+extern void ShowRxSetup(void);
+extern void ShowSetup(boolean);
+extern uint8 MakeUpper(uint8);
+extern void ProcessCommand(void);
+
+extern const uint8 SerHello[];
+extern const uint8 SerSetup[];
+extern const uint8 SerPrompt[];
+
+extern const uint8 RxChMnem[];
+
+//______________________________________________________________________________________________
+
+// nonvolatiles.c
+
+extern void CheckSDCardValid(void);
+
+extern void CreateLogfile(void);
+extern void CloseLogfile(void);
+extern void TxLogChar(uint8);
+
+extern void WritePXImagefile(void);
+extern boolean ReadPXImagefile(void);
+extern int8 ReadPX(uint16);
+extern int16 Read16PX(uint16);
+extern int32 Read32PX(uint16);
+extern void WritePX(uint16, int8);
+extern void Write16PX(uint16, int16);
+extern void Write32PX(uint16, int32);
+
+extern FILE *pxfile;
+extern FILE *newpxfile;
+
+extern const int PX_LENGTH;
+extern int8 PX[], PXNew[];
+
+//______________________________________________________________________________________________
+
+// outputs.c
+
+#define OUT_MINIMUM            1.0              // Required for PPM timing loops
+#define OUT_MAXIMUM            200.0            // to reduce Rx capture and servo pulse output interaction
+#define OUT_NEUTRAL            105.0            // 1.503mS @ 105 16MHz
+#define OUT_HOLGER_MAXIMUM     225.0
+#define OUT_YGEI2C_MAXIMUM     240.0
+#define OUT_X3D_MAXIMUM        200.0
+
+extern uint8 SaturInt(int16);
+extern void DoMulticopterMix(real32 CurrThrottle);
+extern void CheckDemand(real32 CurrThrottle);
+extern void MixAndLimitMotors(void);
+extern void MixAndLimitCam(void);
+extern void OutSignals(void);
+extern void InitI2CESCs(void);
+extern void StopMotors(void);
+extern void ExercisePWM(void);
+extern void InitMotors(void);
+
+enum PWMCamTags { CamRollC = 6, CamPitchC = 7 };
+enum PWMQuadTags {FrontC=0, BackC, RightC, LeftC }; // order is important for X3D & Holger ESCs
+enum PWMConvTags {ThrottleC=0, AileronC, ElevatorC, RudderC, RTHC };
+enum PWMWingTags3 {RightElevonC=1, LeftElevonC=2};
+enum PWMVTTags {FrontLeftC=0, FrontRightC};
+enum PWMY6Tags {FrontTC=0, LeftTC, RightTC, FrontBC, LeftBC, RightBC };
+enum PWMHexTags {FrontHC=0, FrontLeftHC, FrontRightHC, BackLeftHC, BackRightHC,BackHC };
+
+//#define NoOfPWMOutputs            4
+#define NoOfI2CESCOutputs         4
+
+extern const real32 PWMScale;
+
+extern real32 PWM[8];
+extern real32 PWMSense[8];
+extern int16 ESCI2CFail[6];
+extern int16 CurrThrottle;
+extern int16 CamRollPulseWidth, CamPitchPulseWidth;
+extern int16 ESCMin, ESCMax;
+
+//______________________________________________________________________________________________
+
+// params.c
+
+extern void ReadParameters(void);
+extern void UseDefaultParameters(void);
+extern void UpdateParamSetChoice(void);
+extern boolean ParameterSanityCheck(void);
+extern void InitParameters(void);
+
+enum TxRxTypes {
+    FutabaCh3, FutabaCh2, FutabaDM8, JRPPM, JRDM9, JRDXS12,
+    DX7AR7000, DX7AR6200, FutabaCh3_6_7, DX7AR6000, GraupnerMX16s, DX6iAR6200, FutabaCh3_R617FS,
+    DX7aAR7000, ExternalDecoder, FrSkyDJT_D8R, UnknownTxRx, CustomTxRx
+};
+enum RCControls {ThrottleRC, RollRC, PitchRC, YawRC, RTHRC, CamPitchRC, NavGainRC};
+enum ESCTypes { ESCPPM, ESCHolger, ESCX3D, ESCYGEI2C };
+enum AFs { QuadAF, TriAF, VTAF, Y6AF, HeliAF, ElevAF, AilAF };
+
+enum Params { // MAX 64
+    RollKp,                // 01
+    RollKi,                // 02
+    RollKd,                // 03
+    HorizDampKp,           // 04c
+    RollIntLimit,          // 05
+    PitchKp,               // 06
+    PitchKi,               // 07
+    PitchKd,               // 08
+    AltKp,                 // 09c
+    PitchIntLimit,         // 10
+
+    YawKp,                 // 11
+    YawKi,                 // 12
+    YawKd,                 // 13
+    YawLimit,              // 14
+    YawIntLimit,           // 15
+    ConfigBits,            // 16c
+    unused17 ,             // 17 TimeSlots
+    LowVoltThres,          // 18c
+    CamRollKp,             // 19
+    PercentCruiseThr,      // 20c
+
+    VertDampKp,            // 21c
+    MiddleUD,              // 22c
+    PercentIdleThr,        // 23c
+    MiddleLR,              // 24c
+    MiddleBF,              // 25c
+    CamPitchKp,            // 26
+    CompassKp,             // 27
+    AltKi,                 // 28c
+    unused29 ,             // 29 NavRadius
+    NavKi,                 // 30
+
+    GSThrottle,            // 31
+    Acro,                  // 32
+    NavRTHAlt,             // 33
+    NavMagVar,             // 34c
+    GyroRollPitchType,     // 35
+    ESCType,               // 36
+    TxRxType,              // 37
+    NeutralRadius,         // 38
+    PercentNavSens6Ch,     // 39
+    CamRollTrim,           // 40
+    NavKd,                 // 41
+    VertDampDecay,         // 42
+    HorizDampDecay,        // 43
+    BaroScale,             // 44
+    TelemetryType,         // 45
+    MaxDescentRateDmpS,    // 46
+    DescentDelayS,         // 47
+    NavIntLimit,           // 48
+    AltIntLimit,           // 49
+    unused50,              // 50 GravComp
+    unused51 ,             // 51 CompSteps
+    ServoSense,            // 52
+    CompassOffsetQtr,      // 53
+    BatteryCapacity,       // 54
+    unused55,              // 55 GyroYawType
+    AltKd,                 // 56
+    Orient,                // 57
+    NavYawLimit,           // 58
+    Balance                // 59
+
+    // 56 - 64 unused currently
+};
+
+//#define FlyXMode                 0
+//#define FlyAltOrientationMask    0x01
+
+#define UsePositionHoldLock      0
+#define UsePositionHoldLockMask  0x01
+
+#define UseRTHDescend            1
+#define UseRTHDescendMask        0x02
+
+#define TxMode2                  2
+#define TxMode2Mask              0x04
+
+#define RxSerialPPM              3
+#define RxSerialPPMMask          0x08
+
+#define RFInches                 4
+#define RFInchesMask             0x10
+
+// bit 4 is pulse polarity for 3.15
+
+#define UseUseAngleControl       5
+#define UseAngleControlMask      0x20
+
+#define UsePolar                 6
+#define UsePolarMask             0x40
+
+// bit 7 unusable in UAVPSet
+
+extern const int8 DefaultParams[MAX_PARAMETERS][2];
+
+extern const uint8 ESCLimits [];
+
+extern real32 OSin[], OCos[];
+extern uint8 Orientation, PolarOrientation;
+
+extern uint8 ParamSet;
+extern boolean ParametersChanged, SaveAllowTurnToWP;
+extern int8 P[];
+extern real32 K[MAX_PARAMETERS]; // Arm rescaled legacy parameters as appropriate
+
+extern uint8 UAVXAirframe;
+
+//__________________________________________________________________________________________
+
+// rc.c
+
+extern void DoRxPolarity(void);
+extern void InitRC(void);
+extern void MapRC(void);
+extern void CheckSticksHaveChanged(void);
+extern void UpdateControls(void);
+extern void CaptureTrims(void);
+extern void CheckThrottleMoved(void);
+extern void ReceiverTest(void);
+
+extern const boolean PPMPosPolarity[];
+extern const uint8 Map[CustomTxRx+1][CONTROLS];
+extern int8 RMap[];
+
+#define PPMQMASK 3
+extern int16 PPMQSum[];
+extern int16x8x4Q PPMQ;
+extern boolean RCPositiveEdge;
+extern int16 RC[], RCp[];
+extern int16 Trim[3];
+extern int16 ThrLow, ThrNeutral, ThrHigh;
+
+//__________________________________________________________________________________________
+
+// serial.c
+
+extern void TxString(const uint8*);
+extern void TxChar(uint8);
+extern void TxValU(uint8);
+extern void TxValS(int8);
+extern void TxBin8(uint8);
+extern void TxNextLine(void);
+extern void TxNibble(uint8);
+extern void TxValH( uint8);
+extern void TxValH16(uint16);
+extern uint8 RxChar(void);
+extern uint8 PollRxChar(void);
+extern uint8 RxNumU(void);
+extern int8 RxNumS(void);
+extern void TxVal32(int32, int8, uint8);
+extern void TxChar(uint8);
+extern void TxESCu8(uint8);
+extern void Sendi16(int16);
+extern void TxESCi8(int8);
+extern void TxESCi16(int16);
+extern void TxESCi24(int24);
+extern void TxESCi32(int32);
+
+//______________________________________________________________________________________________
+
+// stats.c
+
+extern void ZeroStats(void);
+extern void ReadStatsPX(void);
+extern void WriteStatsPX(void);
+extern void ShowStats(void);
+
+enum Statistics {
+    GPSAltitudeS, BaroRelAltitudeS, ESCI2CFailS, GPSMinSatsS, MinROCS, MaxROCS, GPSVelS,
+    AccFailS, CompassFailS, BaroFailS, GPSInvalidS, GPSMaxSatsS, NavValidS,
+    MinHDiluteS, MaxHDiluteS, RCGlitchesS, GPSBaroScaleS, GyroFailS, RCFailsafesS, I2CFailS, MinTempS, MaxTempS, BadS, BadNumS
+}; // NO MORE THAN 32 or 64 bytes
+
+extern int16 Stats[];
+
+//______________________________________________________________________________________________
+
+// telemetry.c
+
+extern void RxTelemetryPacket(uint8);
+extern void InitTelemetryPacket(void);
+extern void BuildTelemetryPacket(uint8);
+
+extern void SendPacketHeader(void);
+extern void SendPacketTrailer(void);
+
+extern void SendTelemetry(void);
+extern void SendUAVX(void);
+extern void SendUAVXControl(void);
+extern void SendFlightPacket(void);
+extern void SendNavPacket(void);
+extern void SendControlPacket(void);
+extern void SendStatsPacket(void);
+extern void SendParamPacket(uint8);
+extern void SendMinPacket(void);
+extern void SendArduStation(void);
+extern void SendCustom(void);
+extern void SensorTrace(void);
+extern void CheckTelemetry(void);
+
+enum TelemetryStates { WaitRxSentinel, WaitRxESC,  WaitRxBody };
+
+
+enum PacketTags {UnknownPacketTag = 0, LevPacketTag, NavPacketTag, MicropilotPacketTag, WayPacketTag,
+                 AirframePacketTag, NavUpdatePacketTag, BasicPacketTag, RestartPacketTag, TrimblePacketTag,
+                 MessagePacketTag, EnvironmentPacketTag, BeaconPacketTag, UAVXFlightPacketTag,
+                 UAVXNavPacketTag, UAVXStatsPacketTag, UAVXControlPacketTag, UAVXParamsPacketTag, UAVXMinPacketTag, FrSkyPacketTag
+                };
+
+enum TelemetryTypes { NoTelemetry, GPSTelemetry, UAVXTelemetry, UAVXControlTelemetry, UAVXMinTelemetry,
+                      ArduStationTelemetry, CustomTelemetry
+                    };
+
+extern uint8 UAVXCurrPacketTag;
+extern uint8 RxPacketLength, RxPacketByteCount;
+extern uint8 RxCheckSum;
+extern uint8 RxPacketTag, ReceivedPacketTag;
+extern uint8 PacketRxState;
+extern boolean CheckSumError, TelemetryPacketReceived;
+
+extern int16 RxLengthErrors, RxTypeErrors, RxCheckSumErrors;
+
+extern uint8 TxCheckSum;
+
+extern FILE *logfile;
+extern boolean EchoToLogFile, LogfileIsOpen;
+extern uint32 LogChars;
+
+//______________________________________________________________________________________________
+
+// temperature.c
+
+#define TMP100_MAX_ADC      4095      // 12 bits
+#define TMP100_ID           0x96
+#define TMP100_WR           0x96      // Write
+#define TMP100_RD           0x97      // Read    
+#define TMP100_TMP          0x00      // Temperature
+#define TMP100_CMD          0x01
+#define TMP100_LOW          0x02      // Alarm low limit
+#define TMP100_HI           0x03      // Alarm high limit
+#define TMP100_CFG          0         // 0.5 deg resolution continuous
+
+extern void GetTemperature(void);
+extern void InitTemperature(void);
+
+extern i16u AmbientTemperature;
+
+//______________________________________________________________________________________________
+
+// utils.c
+
+extern void InitMisc(void);
+extern void Delay1mS(int16);
+extern void Delay100mS(int16);
+extern void DoBeep100mS(uint8, uint8);
+extern void DoStartingBeeps(uint8);
+extern real32 SlewLimit(real32, real32, real32);
+extern real32 DecayX(real32, real32);
+extern void LPFilter(real32*, real32*, real32, real32);
+extern void CheckAlarms(void);
+extern void Timing(uint8, uint32);
+
+typedef struct {
+    uint32 T;
+    uint32 Count;
+} TimingRec;
+
+enum Timed { GetAttitudeT , UnknownT };
+extern TimingRec Times[];
+
+#define TimeS  uint32 TStart;TStart=timer.read_us();
+#define TimeF(w, tf) Time(w, tf)
+
+//______________________________________________________________________________________________
+
+
+// Sanity checks
+
+#if (( defined TRICOPTER + defined QUADROCOPTER + defined VTCOPTER + defined Y6COPTER + defined HELICOPTER + defined AILERON + defined ELEVON ) != 1)
+#error None or more than one aircraft configuration defined !
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UAVXRevision.h	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,24 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#define Version    "ARM"
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/accel.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,362 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+void ShowAccType(void);
+void ReadAccelerometers(void);
+void GetAccelerations(void);
+void GetNeutralAccelerations(void);
+void AccelerometerTest(void);
+void InitAccelerometers(void);
+
+real32 Vel[3], Acc[3], AccNeutral[3], Accp[3];
+int16 NewAccNeutral[3];
+uint8 AccelerometerType;
+
+void ShowAccType(void) {
+    switch ( AccelerometerType ) {
+        case LISLAcc:
+            TxString("LIS3L");
+            break;
+        case ADXL345Acc:
+            TxString("ADXL345");
+            break;
+        case AccUnknown:
+            TxString("unknown");
+            break;
+        default:
+            ;
+    } // switch
+} // ShowAccType
+
+void ReadAccelerometers(void) {
+    switch ( AccelerometerType ) {
+        case LISLAcc:
+            ReadLISLAcc();
+            break;
+        case ADXL345Acc:
+            ReadADXL345Acc();
+            break;
+            // other accelerometers
+        default:
+            Acc[BF] = Acc[LR] = 0.0;
+            Acc[UD] = 1.0;
+            break;
+    } // switch
+} // ReadAccelerometers
+
+void GetNeutralAccelerations(void) {
+    static uint8 i, a;
+    static real32 Temp[3] = {0.0, 0.0, 0.0};
+
+    if ( F.AccelerationsValid ) {
+        for ( i = 16; i; i--) {
+            ReadAccelerometers();
+            for ( a = 0; a <(uint8)3; a++ )
+                Temp[a] += Acc[a];
+        }
+
+        for ( a = 0; a <(uint8)3; a++ )
+            Temp[a] = Temp[a] * 0.0625;
+
+        NewAccNeutral[BF] = Limit((int16)(Temp[BF] * 1000.0 ), -99, 99);
+        NewAccNeutral[LR] = Limit( (int16)(Temp[LR] * 1000.0 ), -99, 99);
+        NewAccNeutral[UD] = Limit( (int16)(( Temp[UD] - 1.0 ) * 1000.0) , -99, 99);
+
+    } else
+        for ( a = 0; a <(uint8)3; a++ )
+            AccNeutral[a] = 0.0;
+
+} // GetNeutralAccelerations
+
+void GetAccelerations(void) {
+
+    static real32 AccA;
+    static uint8 a;
+
+    if ( F.AccelerationsValid ) {
+        ReadAccelerometers();
+
+        // Neutral[ {LR, BF, UD} ] pass through UAVPSet
+        // and come back as AccMiddle[LR] etc.
+
+        Acc[BF] -= K[MiddleBF];
+        Acc[LR] -= K[MiddleLR];
+        Acc[UD] -= K[MiddleUD];
+
+        AccA = dT / ( OneOnTwoPiAccF + dT );
+        for ( a = 0; a < (uint8)3; a++ ) {
+            Acc[a] = Accp[a] + (Acc[a] - Accp[a]) * AccA;
+            Accp[a] = Acc[a];
+        }
+
+    } else {
+        Acc[LR] = Acc[BF] = 0;
+        Acc[UD] = 1.0;
+    }
+} // GetAccelerations
+
+void AccelerometerTest(void) {
+    TxString("\r\nAccelerometer test -");
+    ShowAccType();
+    TxString("\r\nRead once - no averaging\r\n");
+
+    InitAccelerometers();
+
+    if ( F.AccelerationsValid ) {
+        ReadAccelerometers();
+
+        TxString("\tL->R: \t");
+        TxVal32( Acc[LR] * 1000.0, 3, 'G');
+        if ( fabs(Acc[LR]) > 0.2 )
+            TxString(" fault?");
+        TxNextLine();
+
+        TxString("\tB->F: \t");
+        TxVal32( Acc[BF] * 1000.0, 3, 'G');
+        if ( fabs(Acc[BF]) > 0.2 )
+            TxString(" fault?");
+        TxNextLine();
+
+
+        TxString("\tU->D:    \t");
+        TxVal32( Acc[UD] * 1000.0, 3, 'G');
+        if ( fabs(Acc[UD]) > 1.2 )
+            TxString(" fault?");
+        TxNextLine();
+    }
+} // AccelerometerTest
+
+void InitAccelerometers(void) {
+    static uint8 a;
+
+    F.AccelerationsValid = true; // optimistic
+
+    for ( a = 0; a < (uint8)3; a++ ) {
+        NewAccNeutral[a] = Acc[a] = Accp[a] = Vel[a] = 0.0;
+        Comp[a] = 0;
+    }
+    Acc[2] = Accp[2] = 1.0;
+
+    if ( ADXL345AccActive() ) {
+        InitADXL345Acc();
+        AccelerometerType = ADXL345Acc;
+
+    } else
+        if ( LISLAccActive() )
+            AccelerometerType = LISLAcc;
+        else
+            // check for other accs in preferred order
+        {
+            AccelerometerType = AccUnknown;
+            F.AccelerationsValid = false;
+        }
+
+    if ( F.AccelerationsValid ) {
+        LEDYellow_ON;
+        GetNeutralAccelerations();
+        LEDYellow_OFF;
+    } else
+        F.AccFailure = true;
+} // InitAccelerometers
+
+//________________________________________________________________________________________
+
+// ADXL345 3 Axis Accelerometer
+
+void ReadADXL345Acc(void);
+void InitADXL345Acc(void);
+boolean ADXL345AccActive(void);
+
+const float GRAVITY_ADXL345 = 250.0; // ~4mG/LSB
+
+void ReadADXL345Acc(void) {
+
+    static uint8 a, r;
+    static char b[6];
+    static i16u X, Y, Z;
+
+    /*
+    r = 0;
+    while ( r == 0 ) {
+        I2CACC.start();
+        r = I2CACC.write(ADXL345_ID);
+        r = I2CACC.write(0x30);
+        r = I2CACC.read(true) & 0x80;
+        I2CACC.stop();
+    }
+    */
+
+    I2CACC.start();
+    r = I2CACC.write(ADXL345_ID);
+    r = I2CACC.write(0x32); // point to acc data
+    I2CACC.stop();
+
+    I2CACC.read(ADXL345_ID, b, 6);
+
+    X.b1 = b[1];
+    X.b0 = b[0];
+    Y.b1 = b[3];
+    Y.b0  =b[2];
+    Z.b1 = b[5];
+    Z.b0 = b[4];
+
+    if ( F.Using9DOF ) { // SparkFun/QuadroUFO 9DOF breakouts pins forward components up
+        Acc[BF] = -Y.i16;
+        Acc[LR] = -X.i16;
+        Acc[UD] = -Z.i16;
+    } else {// SparkFun 6DOF breakouts pins forward components down 
+        Acc[BF] = -X.i16;
+        Acc[LR] = -Y.i16;
+        Acc[UD] = -Z.i16; 
+    }
+
+    // LP filter here?
+
+    for ( a = 0; a < (int8)3; a++ )
+        Acc[a] /= GRAVITY_ADXL345;
+
+} // ReadADXL345Acc
+
+void InitADXL345Acc() {
+    static uint8 r;
+
+    I2CACC.start();
+    I2CACC.write(ADXL345_W);
+    r = I2CACC.write(0x2D);  // power register
+    r = I2CACC.write(0x08);  // measurement mode
+    I2CACC.stop();
+
+    Delay1mS(5);
+
+    I2CACC.start();
+    r = I2CACC.write(ADXL345_W);
+    r =  I2CACC.write(0x31);  // format
+    r =  I2CACC.write(0x08);  // full resolution, 2g
+    I2CACC.stop();
+
+    Delay1mS(5);
+
+    I2CACC.start();
+    r =  I2CACC.write(ADXL345_W);
+    r =  I2CACC.write(0x2C);  // Rate
+    r =  I2CACC.write(0x09);  // 50Hz, 400Hz 0x0C
+    I2CACC.stop();
+
+    Delay1mS(5);
+
+} // InitADXL345Acc
+
+boolean ADXL345AccActive(void) {
+
+    I2CACC.start();
+    F.AccelerationsValid = I2CACC.write(ADXL345_ID) == I2C_ACK;
+    I2CACC.stop();
+    
+    TrackMinI2CRate(400000);
+     
+    return( true ); //zzz F.AccelerationsValid );
+
+} // ADXL345AccActive
+
+//________________________________________________________________________________________
+
+// LIS3LV02DG Accelerometer 400KHz
+
+void WriteLISL(uint8, uint8);
+void ReadLISLAcc(void);
+boolean LISLAccActive(void);
+
+const float GRAVITY_LISL = 1024.0;
+
+void ReadLISLAcc(void) {
+    static uint8 a;
+    static char b[6];
+    static i16u X, Y, Z;
+
+    F.AccelerationsValid = I2CACC.write(LISL_ID) == I2C_ACK; // Acc still there?
+    if ( F.AccelerationsValid ) {
+
+        // Ax.b0 = I2CACC.write(LISL_OUTX_L + LISL_INCR_ADDR + LISL_READ);
+
+        I2CACC.read(LISL_ID, b, 6);
+
+        X.b1 = b[1];
+        X.b0 = b[0];
+        Y.b1 = b[3];
+        Y.b0 = b[2];
+        Z.b1 = b[5];
+        Z.b0 = b[4];
+
+        Acc[BF] = Z.i16;
+        Acc[LR] = -X.i16;
+        Acc[UD] = Y.i16;
+
+        // LP Filter here?
+
+        for ( a = 0; a < (uint8)3; a++ )
+            Acc[a] /= GRAVITY_LISL;
+
+    } else {
+        for ( a = 0; a < (uint8)3; a++ )
+            Acc[a] = AccNeutral[a];
+        Acc[UD] += 1.0;
+
+        if ( State == InFlight ) {
+            Stats[AccFailS]++;    // data over run - acc out of range
+            // use neutral values!!!!
+            F.AccFailure = true;
+        }
+    }
+} // ReadLISLAccelerometers
+
+void WriteLISL(uint8 d, uint8 a) {
+    I2CACC.start();
+    I2CACC.write(a);
+    I2CACC.write(d);
+    I2CACC.stop();
+} // WriteLISL
+
+boolean LISLAccActive(void) {
+    F.AccelerationsValid = false;
+    /*
+        WriteLISL(0x4a, LISL_CTRLREG_2);           // enable 3-wire, BDU=1, +/-2g
+
+        if ( I2CACC.write(LISL_ID) == I2C_ACK ) {
+            WriteLISL(0xc7, LISL_CTRLREG_1);       // on always, 40Hz sampling rate,  10Hz LP cutoff, enable all axes
+            WriteLISL(0, LISL_CTRLREG_3);
+            WriteLISL(0x40, LISL_FF_CFG);          // latch, no interrupts;
+            WriteLISL(0, LISL_FF_THS_L);
+            WriteLISL(0xFC, LISL_FF_THS_H);        // -0,5g threshold
+            WriteLISL(255, LISL_FF_DUR);
+            WriteLISL(0, LISL_DD_CFG);
+            F.AccelerationsValid = true;
+        } else
+            F.AccFailure = true;
+    */
+    
+    TrackMinI2CRate(400000);
+        
+    return ( false );//F.AccelerationsValid );
+} // LISLAccActive
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/analog.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,117 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses//
+
+#include "UAVXArm.h"
+
+void GetBattery(void);
+void BatteryTest(void);
+void InitBattery(void);
+
+real32 BatteryVolts, BatteryCurrentADCEstimated, BatteryChargeUsedAH;
+real32 BatteryCharge, BatteryCurrent;
+real32 BatteryVoltsScale;
+
+void GetBattery(void) {
+    //  AttoPilot Voltage and Current Sense Breakout SparkFun Part: SEN-09028
+
+    const real32 BatteryCurrentScale = 90.15296;    // Amps FS
+
+    if ( F.HaveBatterySensor ) {
+        BatteryCurrent = BatteryCurrentADC.read() * BatteryCurrentScale;
+        BatteryChargeUsedAH  += BatteryCurrent * (real32)(mSClock() - mS[LastBattery]) * 2.777777e-7;
+        mS[LastBattery] = mSClock();
+    } else
+        BatteryCurrent =  BatteryChargeUsedAH = 0;
+
+    BatteryVolts = BatteryVoltsADC.read() *  BatteryVoltsScale;
+    F.LowBatt = BatteryVolts < K[LowVoltThres];
+
+} // GetBattery
+
+void BatteryTest(void) {
+
+    TxString("\r\nBattery test\r\n");
+
+    GetBattery();
+
+    // Battery
+    TxString("Volts  :\t");
+    TxVal32(BatteryVolts * 10.0, 1, 'V');
+    TxString(" Limit > ");
+    TxVal32( K[LowVoltThres] * 10.0, 1, 'V');
+
+    if ( F.HaveBatterySensor ) {
+        TxString("\r\nCurrent:\t");
+        TxVal32(BatteryCurrent * 10.0, 1, 'A');
+        TxString(" ( ");
+        TxVal32(BatteryChargeUsedAH * 1000.0, 0, 0 );
+        TxString(" mAH )\r\n");
+    } else
+        TxString("\r\nCurrent:\tnot available - no battery sensor\r\n");
+
+} // BatteryTest
+
+void InitBattery() {
+
+    F.HaveBatterySensor = true;
+    GetBattery();
+    F.HaveBatterySensor =  BatteryCurrent < 2.0;
+    if ( F.HaveBatterySensor )
+        BatteryVoltsScale = 51.8144;       // Volts FS
+    else
+        BatteryVoltsScale = BATTERY_VOLTS_SCALE;
+
+} // InitBattery
+
+//_____________________________________________________________________
+
+void GetRangefinderAltitude(void);
+void InitRangefinder(void);
+
+real32 RangefinderAltitude;
+
+const real32 RangefinderScale = 10.24; // Metres FS
+
+void GetRangefinderAltitude(void) {
+
+    if ( F.RangefinderAltitudeValid ) {
+        RangefinderAltitude = RangefinderADC.read() * RangefinderScale;
+        if ( F.RFInInches )
+            RangefinderAltitude *= 2.54;
+
+        if (( RangefinderAltitude < ALT_RF_ENABLE_M ) && !F.UsingRangefinderAlt)
+            F.UsingRangefinderAlt = true;
+        else
+            if (( RangefinderAltitude > ALT_RF_DISABLE_M ) && F.UsingRangefinderAlt)
+                F.UsingRangefinderAlt = false;
+    } else {
+        RangefinderAltitude = 0.0;
+        F.UsingRangefinderAlt = false;
+    }
+} // GetRangefinderAltitude
+
+void InitRangefinder(void) {
+
+    F.RangefinderAltitudeValid = true;
+    GetRangefinderAltitude();
+    F.RangefinderAltitudeValid = RangefinderAltitude < 1.0; // => supply not RF
+    GetRangefinderAltitude();
+
+} // InitRangefinder
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/attitude.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,602 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+//#define USE_GYRO_RATE
+
+// Reference frame is positive X forward, Y left, Z down, Roll right, Pitch up, Yaw CW.
+
+void AttitudeFailsafeEstimate(void);
+void DoLegacyYawComp(void);
+void AttitudeTest(void);
+
+real32 dT, HalfdT, dTR, dTmS;
+uint32 uSp;
+uint8 AttitudeMethod = PremerlaniDCM; //MadgwickIMU PremerlaniDCM MadgwickAHRS;
+
+void AttitudeFailsafeEstimate(void) {
+
+    static uint8 i;
+
+    for ( i = 0; i < (uint8)3; i++ ) {
+        Rate[i] = Gyro[i];
+        Angle[i] += Rate[i] * dTmS;
+    }
+} // AttitudeFailsafeEstimate
+
+void DoLegacyYawComp(void) {
+
+    static real32 Temp, HE;
+
+    if ( F.CompassValid ) {
+        // + CCW
+        Temp = DesiredYaw - Trim[Yaw];
+        if ( fabs(Temp) > COMPASS_MIDDLE ) { // acquire new heading
+            DesiredHeading = Heading;
+            HE = 0.0;
+        } else {
+            HE = MakePi(DesiredHeading - Heading);
+            HE = Limit(HE, -SIXTHPI, SIXTHPI); // 30 deg limit
+            HE = HE * K[CompassKp];
+            Rate[Yaw] -= Limit(HE, -COMPASS_MAXDEV, COMPASS_MAXDEV);
+        }
+    }
+
+    Angle[Yaw] += Rate[Yaw];
+    Angle[Yaw] = Limit(Angle[Yaw], -K[YawIntLimit], K[YawIntLimit]);
+
+    Angle[Yaw] = DecayX(Angle[Yaw], 0.0002);                 // GKE added to kill gyro drift
+
+} // DoLegacyYawComp
+
+void GetAttitude(void) {
+
+    static uint32 Now;
+    static uint8 i;
+
+    if ( GyroType == IRSensors )
+        GetIRAttitude();
+    else {
+        GetGyroRates();
+        GetAccelerations();
+    }
+
+    if ( mSClock() > mS[CompassUpdate] ) {
+        mS[CompassUpdate] = mSClock() + COMPASS_UPDATE_MS;
+        GetHeading();
+#ifndef USE_DCM_YAW
+        DoLegacyYawComp();
+#endif // !USE_DCM_YAW
+    }
+
+    Now = uSClock();
+    dT = ( Now - uSp) * 0.000001;
+    HalfdT = 0.5 * dT;
+    dTR = 1.0 / dT;
+    uSp = Now;
+
+    if ( GyroType == IRSensors ) {
+
+        for ( i = 0; i < (uint8)2; i++ ) {
+            Rate[i] = ( Angle[i] - Anglep[i] ) * dT;
+            Anglep[i] = Angle[i];
+        }
+
+        Rate[Yaw] = 0.0; // need Yaw gyro!
+
+    } else {
+        DebugPin = true;
+        switch  ( AttitudeMethod ) {
+            case PremerlaniDCM:
+                DCMUpdate();
+                DCMNormalise();
+                DCMDriftCorrection();
+                DCMEulerAngles();
+                break;
+            case MadgwickIMU:
+                IMUupdate(Gyro[Roll], Gyro[Pitch], Gyro[Yaw], Acc[BF], Acc[LR], Acc[UD]);
+                EulerAngles();
+                //   DoLegacyYawComp();
+                break;
+            case MadgwickAHRS: // must have magnetometer
+                AHRSupdate(Gyro[Roll], Gyro[Pitch], Gyro[Yaw], Acc[BF], Acc[LR], Acc[UD], 1,0,0);//Mag[BF].V, Mag[LR].V, Mag[UD].V);
+                EulerAngles();
+                break;
+        } // switch
+
+        DebugPin = false;
+    }
+
+    F.NearLevel = Max(fabs(Angle[Roll]), fabs(Angle[Pitch])) < NAV_RTH_LOCKOUT;
+
+} // GetAttitude
+
+
+void AttitudeTest(void) {
+
+    TxString("\r\nAttitude Test\r\n");
+
+    GetAttitude();
+
+    TxString("\r\ndT \t");
+    TxVal32(dT * 1000.0, 3, 0);
+    TxString(" Sec.\r\n\r\n");
+
+    if ( GyroType == IRSensors ) {
+
+        TxString("IR Sensors:\r\n");
+        TxString("\tRoll \t");
+        TxVal32(IR[Roll] * 100.0, 2, HT);
+        TxNextLine();
+        TxString("\tPitch\t");
+        TxVal32(IR[Pitch] * 100.0, 2, HT);
+        TxNextLine();
+        TxString("\tZ    \t");
+        TxVal32(IR[Yaw] * 100.0, 2, HT);
+        TxNextLine();
+        TxString("\tMin/Max\t");
+        TxVal32(IRMin * 100.0, 2, HT);
+        TxVal32(IRMax * 100.0, 2, HT);
+        TxString("\tSwing\t");
+        TxVal32(IRSwing * 100.0, 2, HT);
+        TxNextLine();
+
+    } else {
+
+        TxString("Rates (Raw and Compensated):\r\n");
+        TxString("\tRoll \t");
+        TxVal32(Gyro[Roll] * MILLIANGLE, 3, HT);
+        TxVal32(Rate[Roll] * MILLIANGLE, 3, 0);
+        TxNextLine();
+        TxString("\tPitch\t");
+        TxVal32(Gyro[Pitch] * MILLIANGLE, 3, HT);
+        TxVal32(Rate[Pitch] * MILLIANGLE, 3, 0);
+        TxNextLine();
+        TxString("\tYaw  \t");
+        TxVal32(Gyro[Yaw] * MILLIANGLE, 3, HT);
+        TxVal32(Rate[Yaw] * MILLIANGLE, 3, 0);
+        TxNextLine();
+
+        TxString("Accelerations:\r\n");
+        TxString("\tB->F \t");
+        TxVal32(Acc[BF] * 1000.0, 3, 0);
+        TxNextLine();
+        TxString("\tL->R \t");
+        TxVal32(Acc[LR] * 1000.0, 3, 0);
+        TxNextLine();
+        TxString("\tU->D \t");
+        TxVal32(Acc[UD] * 1000.0, 3, 0);
+        TxNextLine();
+    }
+
+    if ( CompassType != HMC6352 ) {
+        TxString("Magnetic:\r\n");
+        TxString("\tX    \t");
+        TxVal32(Mag[Roll].V, 0, 0);
+        TxNextLine();
+        TxString("\tY    \t");
+        TxVal32(Mag[Pitch].V, 0, 0);
+        TxNextLine();
+        TxString("\tZ    \t");
+        TxVal32(Mag[Yaw].V, 0, 0);
+        TxNextLine();
+    }
+
+    TxString("Compass: \t");
+    TxVal32(Make2Pi(MagHeading) * MILLIANGLE, 3, 0);
+    TxNextLine();
+
+} // AttitudeTest
+
+//____________________________________________________________________________________________
+
+// The DCM formulation used here is due to W. Premerlani and P. Bizard in a paper entitled:
+// Direction Cosine Matrix IMU: Theory, Draft 17 June 2009. This paper draws upon the original
+// work by R. Mahony et al. - Thanks Rob!
+
+void DCMNormalise(void);
+void DCMDriftCorrection(void);
+void DCMMotionCompensation(void);
+void DCMUpdate(void);
+void DCMEulerAngles(void);
+
+// requires rescaling for the much faster PID cycle in UAVXArm
+// guess x5 initially
+#define Kp_RollPitch 25.0       // 5.0
+#define Ki_RollPitch 0.025      // 0.005
+#define Kp_Yaw 1.2
+#define Ki_Yaw 0.00002
+
+real32   RollPitchError[3] = {0,0,0};
+real32   OmegaV[3] = {0,0,0}; // corrected gyro data
+real32   OmegaP[3] = {0,0,0}; // proportional correction
+real32   OmegaI[3] = {0,0,0}; // integral correction
+real32   Omega[3] = {0,0,0};
+real32   DCM[3][3] = {{1,0,0 },{0,1,0} ,{0,0,1}};
+real32   U[3][3] = {{0,1,2},{ 3,4,5} ,{6,7,8}};
+real32   TempM[3][3] = {{0,0,0},{0,0,0},{ 0,0,0}};
+
+void DCMNormalise(void) {
+
+    static real32 Error = 0;
+    static real32 Renorm = 0.0;
+    static boolean Problem;
+    static uint8 r;
+
+    Error = -VDot(&DCM[0][0], &DCM[1][0]) * 0.5;        //eq.19
+
+    VScale(&TempM[0][0], &DCM[1][0], Error);            //eq.19
+    VScale(&TempM[1][0], &DCM[0][0], Error);            //eq.19
+
+    VAdd(&TempM[0][0], &TempM[0][0], &DCM[0][0]);       //eq.19
+    VAdd(&TempM[1][0], &TempM[1][0], &DCM[1][0]);       //eq.19
+
+    VCross(&TempM[2][0],&TempM[0][0], &TempM[1][0]);    // c= a * b eq.20
+
+    Problem = false;
+    for ( r = 0; r < (uint8)3; r++ ) {
+        Renorm = VDot(&TempM[r][0],&TempM[r][0]);
+        if ( (Renorm <  1.5625) && (Renorm > 0.64) )
+            Renorm = 0.5 * (3.0 - Renorm);               //eq.21
+        else
+            if ( (Renorm < 100.0) && (Renorm > 0.01) )
+                Renorm = 1.0 / sqrt( Renorm );
+            else
+                Problem = true;
+
+        VScale(&DCM[r][0], &TempM[r][0], Renorm);
+    }
+
+    if ( Problem ) { // Divergent - force to initial conditions and hope!
+        DCM[0][0] = 1.0;
+        DCM[0][1] = 0.0;
+        DCM[0][2] = 0.0;
+        DCM[1][0] = 0.0;
+        DCM[1][1] = 1.0;
+        DCM[1][2] = 0.0;
+        DCM[2][0] = 0.0;
+        DCM[2][1] = 0.0;
+        DCM[2][2] = 1.0;
+    }
+
+} // DCMNormalise
+
+void DCMMotionCompensation(void) {
+    // compensation for rate of change of velocity LR/BF needs GPS velocity but
+    // updates probably too slow?
+    Acc[LR ] += 0.0;
+    Acc[BF] += 0.0;
+} // DCMMotionCompensation
+
+void DCMDriftCorrection(void) {
+
+    static real32 ScaledOmegaP[3], ScaledOmegaI[3];
+    static real32 YawError[3];
+    static real32 AccMagnitude, AccWeight;
+    static real32 ErrorCourse;
+
+    AccMagnitude = sqrt( Sqr(Acc[0]) + Sqr(Acc[1]) + Sqr(Acc[2]) );
+
+    // dynamic weighting of Accelerometer info (reliability filter)
+    // weight for Accelerometer info ( < 0.5G = 0.0, 1G = 1.0 , > 1.5G = 0.0)
+    AccWeight = Limit(1.0 - 2.0 * fabs(1.0 - AccMagnitude), 0.0, 1.0);
+
+    VCross(&RollPitchError[0], &Acc[0], &DCM[2][0]); //adjust the reference ground
+    VScale(&OmegaP[0], &RollPitchError[0], Kp_RollPitch * AccWeight);
+
+    VScale(&ScaledOmegaI[0], &RollPitchError[0], Ki_RollPitch * AccWeight);
+    VAdd(&OmegaI[0], &OmegaI[0], &ScaledOmegaI[0]);
+
+#ifdef USE_DCM_YAW
+    // Yaw - drift correction based on compass/magnetometer heading
+    HeadingCos = cos( Heading );
+    HeadingSin = sin( Heading );
+    ErrorCourse = ( U[0][0] * HeadingSin ) - ( U[1][0] * HeadingCos );
+    VScale(YawError, &U[2][0], ErrorCourse );
+
+    VScale(&ScaledOmegaP[0], &YawError[0], Kp_Yaw );
+    VAdd(&OmegaP[0], &OmegaP[0], &ScaledOmegaP[0]);
+
+    VScale(&ScaledOmegaI[0], &YawError[0], Ki_Yaw );
+    VAdd(&OmegaI[0], &OmegaI[0], &ScaledOmegaI[0]);
+#endif // USE_DCM_YAW
+} // DCMDriftCorrection
+
+void DCMUpdate(void) {
+
+    static uint8 i, j, k;
+    static real32 op[3];
+
+    VAdd(&Omega[0], &Gyro[0], &OmegaI[0]);
+    VAdd(&OmegaV[0], &Omega[0], &OmegaP[0]);
+
+//   MotionCompensation();
+
+    U[0][0] =  0.0;
+    U[0][1] = -dT * OmegaV[2];   //-z
+    U[0][2] =  dT * OmegaV[1];   // y
+    U[1][0] =  dT * OmegaV[2];   // z
+    U[1][1] =  0.0;
+    U[1][2] = -dT * OmegaV[0];   //-x
+    U[2][0] = -dT * OmegaV[1];   //-y
+    U[2][1] =  dT * OmegaV[0];   // x
+    U[2][2] =  0.0;
+
+    for ( i = 0; i < (uint8)3; i++ )
+        for ( j = 0; j < (uint8)3; j++ ) {
+            for ( k = 0; k < (uint8)3; k++ )
+                op[k] = DCM[i][k] * U[k][j];
+
+            TempM[i][j] = op[0] + op[1] + op[2];
+        }
+
+    for ( i = 0; i < (uint8)3; i++ )
+        for (j = 0; j < (uint8)3; j++ )
+            DCM[i][j] += TempM[i][j];
+
+} // DCMUpdate
+
+void DCMEulerAngles(void) {
+
+    static uint8 g;
+
+    for ( g = 0; g < (uint8)3; g++ )
+        Rate[g] = Gyro[g];
+
+    Angle[Pitch] = asin(DCM[2][0]);
+    Angle[Roll] = -atan2(DCM[2][1], DCM[2][2]);
+
+#ifdef USE_DCM_YAW
+    Angle[Yaw] = atan2(DCM[1][0], DCM[0][0]);
+#endif // USE_DCM_YAW
+
+} // DCMEulerAngles
+
+//___________________________________________________________________________________
+
+// IMU.c
+// S.O.H. Madgwick
+// 25th September 2010
+
+// Description:
+
+// Quaternion implementation of the 'DCM filter' [Mahony et al.].
+
+// User must define 'HalfdT' as the (sample period / 2), and the filter gains 'MKp' and 'MKi'.
+
+// Global variables 'q0', 'q1', 'q2', 'q3' are the quaternion elements representing the estimated
+// orientation.  See my report for an overview of the use of quaternions in this application.
+
+// User must call 'IMUupdate()' every sample period and parse calibrated gyroscope ('gx', 'gy', 'gz')
+// and accelerometer ('ax', 'ay', 'ay') data.  Gyroscope units are radians/second, accelerometer
+// units are irrelevant as the vector is normalised.
+
+#include <math.h>
+
+void IMUupdate(real32 gx, real32 gy, real32 gz, real32 ax, real32 ay, real32 az);
+
+#define MKp 2.0          // proportional gain governs rate of convergence to accelerometer/magnetometer
+#define MKi 0.005f        // integral gain governs rate of convergence of gyroscope biases
+
+real32 q0 = 1.0, q1 = 0.0, q2 = 0.0, q3 = 0.0;  // quaternion elements representing the estimated orientation
+real32 exInt = 0.0, eyInt = 0.0, ezInt = 0.0;   // scaled integral error
+
+void IMUupdate(real32 gx, real32 gy, real32 gz, real32 ax, real32 ay, real32 az) {
+
+    static real32 rnorm;
+    static real32 vx, vy, vz;
+    static real32 ex, ey, ez;
+    static real32 aMag;
+
+//swap z and y?
+
+    // normalise the measurements
+    aMag = sqrt(Sqr(ax) + Sqr(ay) + Sqr(az)); // zero Acc values into AHRS is FATAL
+    if ( aMag < 0.9 ) {
+        ax = ay = 0.0;
+        az = 1.0;
+    } else {
+        rnorm = 1.0/aMag;
+        ax *= rnorm;
+        ay *= rnorm;
+        az *= rnorm;
+    }
+
+    // estimated direction of gravity
+    vx = 2.0*(q1*q3 - q0*q2);
+    vy = 2.0*(q0*q1 + q2*q3);
+    vz = Sqr(q0) - Sqr(q1) - Sqr(q2) + Sqr(q3);
+
+    // error is sum of cross product between reference direction of field and direction measured by sensor
+    ex = (ay*vz - az*vy);
+    ey = (az*vx - ax*vz);
+    ez = (ax*vy - ay*vx);
+
+    // integral error scaled integral gain
+    exInt += ex*MKi;
+    eyInt += ey*MKi;
+    ezInt += ez*MKi;
+
+    // adjusted gyroscope measurements
+    gx += MKp*ex + exInt;
+    gy += MKp*ey + eyInt;
+    gz += MKp*ez + ezInt;
+
+    // integrate quaternion rate and normalise
+    q0 += (-q1*gx - q2*gy - q3*gz)*HalfdT;
+    q1 += (q0*gx + q2*gz - q3*gy)*HalfdT;
+    q2 += (q0*gy - q1*gz + q3*gx)*HalfdT;
+    q3 += (q0*gz + q1*gy - q2*gx)*HalfdT;
+
+    // normalise quaternion
+    rnorm = 1.0/sqrt(Sqr(q0) + Sqr(q1) + Sqr(q2) + Sqr(q3));
+    q0 *= rnorm;
+    q1 *= rnorm;
+    q2 *= rnorm;
+    q3 *= rnorm;
+
+}  // IMUupdate
+
+//_________________________________________________________________________________
+
+// AHRS.c
+// S.O.H. Madgwick
+// 25th August 2010
+
+// Description:
+
+// Quaternion implementation of the 'DCM filter' [Mahoney et al].  Incorporates the magnetic distortion
+// compensation algorithms from my filter [Madgwick] which eliminates the need for a reference
+// direction of flux (bx bz) to be predefined and limits the effect of magnetic distortions to yaw
+// axis only.
+
+// User must define 'HalfdT' as the (sample period / 2), and the filter gains 'MKp' and 'MKi'.
+
+// Global variables 'q0', 'q1', 'q2', 'q3' are the quaternion elements representing the estimated
+// orientation.  See my report for an overview of the use of quaternions in this application.
+
+// User must call 'AHRSupdate()' every sample period and parse calibrated gyroscope ('gx', 'gy', 'gz'),
+// accelerometer ('ax', 'ay', 'ay') and magnetometer ('mx', 'my', 'mz') data.  Gyroscope units are
+// radians/second, accelerometer and magnetometer units are irrelevant as the vector is normalised.
+
+void AHRSupdate(real32 gx, real32 gy, real32 gz, real32 ax, real32 ay, real32 az, real32 mx, real32 my, real32 mz) {
+
+    static real32 rnorm;
+    static real32 hx, hy, hz, bx2, bz2, mx2, my2, mz2;
+    static real32 vx, vy, vz, wx, wy, wz;
+    static real32 ex, ey, ez;
+    static real32 q0q0, q0q1, q0q2, q0q3, q1q1, q1q2, q1q3, q2q2, q2q3, q3q3;
+    static real32 aMag;
+
+    // auxiliary variables to reduce number of repeated operations
+    q0q0 = q0*q0;
+    q0q1 = q0*q1;
+    q0q2 = q0*q2;
+    q0q3 = q0*q3;
+    q1q1 = q1*q1;
+    q1q2 = q1*q2;
+    q1q3 = q1*q3;
+    q2q2 = q2*q2;
+    q2q3 = q2*q3;
+    q3q3 = q3*q3;
+
+    aMag = sqrt(Sqr(ax) + Sqr(ay) + Sqr(az)); // zero values into AHRS is FATAL
+    if ( aMag < 0.9 ) {
+        ax = ay = 0.0;
+        az = 1.0;
+    } else {
+        // normalise the measurements
+        rnorm = 1.0/aMag;
+        ax *= rnorm;
+        ay *= rnorm;
+        az *= rnorm;
+    }
+
+    rnorm = 1.0/sqrt(Sqr(mx) + Sqr(my) + Sqr(mz));
+    mx *= rnorm;
+    my *= rnorm;
+    mz *= rnorm;
+    mx2 = 2.0 * mx;
+    my2 = 2.0 * my;
+    mz2 = 2.0 * mz;
+
+    // compute reference direction of flux
+    hx = mx2*(0.5 - q2q2 - q3q3) + my2*(q1q2 - q0q3) + mz2*(q1q3 + q0q2);
+    hy = mx2*(q1q2 + q0q3) + my2*(0.5 - q1q1 - q3q3) + mz2*(q2q3 - q0q1);
+    hz = mx2*(q1q3 - q0q2) + my2*(q2q3 + q0q1) + mz2*(0.5 - q1q1 - q2q2);
+    bx2 = 2.0*sqrt(Sqr(hx) + Sqr(hy));
+    bz2 = 2.0*hz;
+
+    // estimated direction of gravity and flux (v and w)
+    vx = 2.0*(q1q3 - q0q2);
+    vy = 2.0*(q0q1 + q2q3);
+    vz = q0q0 - q1q1 - q2q2 + q3q3;
+
+    wx = bx2*(0.5 - q2q2 - q3q3) + bz2*(q1q3 - q0q2);
+    wy = bx2*(q1q2 - q0q3) + bz2*(q0q1 + q2q3);
+    wz = bx2*(q0q2 + q1q3) + bz2*(0.5 - q1q1 - q2q2);
+
+    // error is sum of cross product between reference direction of fields and direction measured by sensors
+    ex = (ay*vz - az*vy) + (my*wz - mz*wy);
+    ey = (az*vx - ax*vz) + (mz*wx - mx*wz);
+    ez = (ax*vy - ay*vx) + (mx*wy - my*wx);
+
+    // integral error scaled integral gain
+    exInt += ex*MKi;
+    eyInt += ey*MKi;
+    ezInt += ez*MKi;
+
+    // adjusted gyroscope measurements
+    gx += MKp*ex + exInt;
+    gy += MKp*ey + eyInt;
+    gz += MKp*ez + ezInt;
+
+    // integrate quaternion rate and normalise
+    q0 += (-q1*gx - q2*gy - q3*gz)*HalfdT;
+    q1 += (q0*gx + q2*gz - q3*gy)*HalfdT;
+    q2 += (q0*gy - q1*gz + q3*gx)*HalfdT;
+    q3 += (q0*gz + q1*gy - q2*gx)*HalfdT;
+
+    // normalise quaternion
+    rnorm = 1.0/sqrt(Sqr(q0) + Sqr(q1) + Sqr(q2) + Sqr(q3));
+    q0 *= rnorm;
+    q1 *= rnorm;
+    q2 *= rnorm;
+    q3 *= rnorm;
+
+} // AHRSupdate
+
+void  EulerAngles(void) {
+
+    static uint8 g;
+
+    Angle[Roll] = atan2(2.0*q2*q3 - 2.0*q0*q1 , 2.0*Sqr(q0) + 2.0*Sqr(q3) - 1.0);
+    Angle[Pitch] = asin(2.0*q1*q2 - 2.0*q0*q2);
+    Angle[Yaw] = -atan2(2.0*q1*q2 - 2.0*q0*q3 ,  2.0*Sqr(q0) + 2.0*Sqr(q1) - 1.0);
+
+    for ( g = 0; g < (uint8)3; g++ ) {
+#ifdef USE_GYRO_RATE
+        Rate[g] = Gyro[g];
+#else
+        Rate[g] = ( Angle[g] - Anglep[g] ) * dTR;
+        Anglep[g] = Angle[g];
+#endif // USE_GYRO_RATE
+    }
+
+} // EulerAngles
+
+/*
+heading = atan2(2*qy*qw-2*qx*qz , 1 - 2*qy2 - 2*qz2)
+attitude = asin(2*qx*qy + 2*qz*qw)
+bank = atan2(2*qx*qw-2*qy*qz , 1 - 2*qx2 - 2*qz2)
+
+except when qx*qy + qz*qw = 0.5 (north pole)
+which gives:
+heading = 2 * atan2(x,w)
+bank = 0
+and when qx*qy + qz*qw = -0.5 (south pole)
+which gives:
+heading = -2 * atan2(x,w)
+bank = 0
+*/
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/autonomous.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,586 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+void DoShutdown(void);
+void DoPolarOrientation(void);
+void Navigate(int32, int32);
+void SetDesiredAltitude(int16);
+void DoFailsafeLanding(void);
+void AcquireHoldPosition(void);
+void NavGainSchedule(int16);
+void DoNavigation(void);
+void DoPPMFailsafe(void);
+void UAVXNavCommand(void);
+void GetWayPointPX(int8);
+void InitNavigation(void);
+
+real32 NavCorr[3], NavCorrp[3];
+real32 NavE[3], NavEp[3], NavIntE[3];
+int16 NavYCorrLimit;
+
+#ifdef SIMULATE
+int16 FakeDesiredRoll, FakeDesiredPitch, FakeDesiredYaw, FakeHeading;
+#endif // SIMULATE
+
+typedef union {
+    uint8 b[256];
+    struct {
+        uint8 u0;
+        int16 u1;
+        int8 u3;
+        int8 u4;
+        uint16 u5;
+        uint16 u6;
+        uint8 NoOfWPs;
+        uint8 ProximityAltitude;
+        uint8 ProximityRadius;
+        int16 OriginAltitude;
+        int32 OriginLatitude;
+        int32 OriginLongitude;
+        int16 RTHAltitude;
+        struct {
+            int32 Latitude;
+            int32 Longitude;
+            int16 Altitude;
+            int8 Loiter;
+        } WP[23];
+    };
+} UAVXNav;
+
+uint8 BufferPX[256];
+
+int8     CurrWP;
+int8     NoOfWayPoints;
+int16    WPAltitude;
+int32    WPLatitude, WPLongitude;
+int24    WPLoiter;
+
+real32   WayHeading;
+real32   NavPolarRadius, NavNeutralRadius, NavProximityRadius, NavProximityAltitude;
+int24    NavRTHTimeoutmS;
+
+int8     NavState;
+int16    NavSensitivity, RollPitchMax;
+int16    AltSum;
+
+void DoShutdown(void)
+{
+    State = Shutdown;
+    DesiredThrottle = 0;
+    StopMotors();
+} // DoShutdown
+
+void SetDesiredAltitude(int16 NewDesiredAltitude) { // Metres
+    if ( F.AllowNavAltitudeHold && F.AltHoldEnabled ) {
+        AltSum = 0;
+        DesiredAltitude = NewDesiredAltitude * 10L; // Decimetres
+    }
+} // SetDesiredAltitude
+
+void DoFailsafeLanding(void) {
+    // InTheAir micro switch RC0 Pin 11 to ground when landed
+    
+    const boolean InTheAir = true;
+
+    DesiredAltitude = -20.0;
+if ( F.BaroAltitudeValid )
+    {
+        if ( Altitude > LAND_M )
+            mS[NavStateTimeout] = mSClock() + NAV_RTH_LAND_TIMEOUT_MS;
+
+        if ( !InTheAir || (( mSClock() > mS[NavStateTimeout] ) 
+            && ( F.ForceFailsafe || ( NavState == Touchdown ) || (FailState == Terminated))) )
+            DoShutdown();
+        else
+            DesiredThrottle = CruiseThrottle;
+    }
+    else
+    {
+        if ( mSClock() > mS[DescentUpdate] )
+        {
+            mS[DescentUpdate] = mSClock() + ALT_DESCENT_UPDATE_MS;
+            DesiredThrottle = CruiseThrottle - DescentComp;
+            if ( DesiredThrottle < IdleThrottle )
+                StopMotors();
+            else
+                if ( DescentComp < CruiseThrottle )
+                    DescentComp++;        
+        }
+    }
+} // DoFailsafeLanding
+
+void FailsafeHoldPosition(void) {
+    DesiredRoll = DesiredPitch = DesiredYaw = 0;
+    if ( F.GPSValid && F.CompassValid )
+        Navigate(HoldLatitude, HoldLongitude);
+} // FailsafeHoldPosition
+
+void AcquireHoldPosition(void) {
+    static int8 i;
+
+    for ( i = 0; i < (uint8)3; i++ )
+        NavCorr[i] = NavCorrp[i]  =  0;
+
+    F.NavComputed = false;
+
+    HoldLatitude = GPSLatitude;
+    HoldLongitude = GPSLongitude;
+    F.WayPointAchieved = F.WayPointCentred = F.AcquireNewPosition = false;
+
+    NavState = HoldingStation;
+} // AcquireHoldPosition
+
+void DoPolarOrientation(void) {
+    static real32 EastDiff, NorthDiff, Radius;
+    static real32 DesiredRelativeHeading;
+    static int16 P;
+
+    F.UsingPolar = F.UsingPolarCoordinates && F.NavValid && ( NavState == HoldingStation );
+
+    if ( F.UsingPolar ) { // needs rethink - probably arm using RTH switch
+        EastDiff = (OriginLongitude - GPSLongitude) * GPSLongitudeCorrection;
+        NorthDiff = OriginLatitude - GPSLatitude;
+
+        Radius = Max(abs(EastDiff), abs(NorthDiff));
+        if ( Radius > NavPolarRadius ) {
+            DesiredRelativeHeading = Make2Pi(atan2((real32)EastDiff, (real32)NorthDiff) - PI - Heading );
+
+            P = ( (int24)DesiredRelativeHeading * 24L + HALFPI )/ PI + Orientation;
+
+            while ( P > 24 ) P -=24;
+            while ( P < 0 ) P +=24;
+
+        } else
+            P = 0;
+    } else
+        P = 0;
+
+    PolarOrientation = P;;
+
+} // DoPolarOrientation
+
+void Navigate(int32 NavLatitude, int32 NavLongitude ) {
+    // F.GPSValid must be true immediately prior to entry
+    // This routine does not point the quadrocopter at the destination
+    // waypoint. It simply rolls/pitches towards the destination.
+    // GPS coordinates MUST be int32 to allow sufficient range - real32 is insufficient.
+
+    static real32 RelHeadingSin, RelHeadingCos;
+    static real32 Radius;
+    static real32 AltE;
+    static real32 EastDiff, NorthDiff;
+    static real32 RelHeading;
+    static uint8 a;
+    static real32 Diff, NavP, NavI, NavD;
+
+    DoPolarOrientation();
+
+    DesiredLatitude = NavLatitude;
+    DesiredLongitude = NavLongitude;
+
+    EastDiff = (real32)(DesiredLongitude - GPSLongitude) * GPSLongitudeCorrection;
+    NorthDiff = (real32)(DesiredLatitude - GPSLatitude);
+
+    Radius = sqrt( Sqr(EastDiff) + Sqr(NorthDiff) );
+
+    F.WayPointCentred =  Radius < NavNeutralRadius;
+    AltE = DesiredAltitude - Altitude;
+    F.WayPointAchieved = ( Radius < NavProximityRadius ) && ( abs(AltE) < NavProximityAltitude );
+
+    WayHeading = Make2Pi(atan2((real32)EastDiff, (real32)NorthDiff));
+    RelHeading = MakePi(WayHeading - Heading); // make +/- MilliPi
+
+    if ( ( NavSensitivity > NAV_SENS_THRESHOLD ) && !F.WayPointCentred ) {
+#ifdef NAV_WING
+
+        // no Nav for conventional aircraft - yet!
+        NavCorr[Pitch] = -5; // always moving forward
+        // Just use simple rudder only for now.
+        if ( !F.WayPointAchieved ) {
+            NavCorr[Yaw] = -(RelHeading * NAV_YAW_LIMIT) / HALFPI;
+            NavCorr[Yaw] = Limit(NavCorr[Yaw], -NAV_YAW_LIMIT, NAV_YAW_LIMIT); // gently!
+        }
+
+#else // MULTICOPTER
+
+        // revert to original simpler version from UAVP->UAVX transition
+
+        RelHeadingSin = sin(RelHeading);
+        RelHeadingCos = cos(RelHeading);
+
+        NavE[Roll] = Radius * RelHeadingSin;
+        NavE[Pitch] = -Radius * RelHeadingCos;
+
+        // Roll & Pitch
+
+        for ( a = 0; a < (uint8)2 ; a++ ) {
+            NavP = Limit(NavE[a], -NAV_MAX_ROLL_PITCH, NAV_MAX_ROLL_PITCH);
+
+            NavIntE[a] += NavE[a];
+            NavIntE[a] = Limit(NavIntE[a], -K[NavIntLimit], K[NavIntLimit]);
+            NavI = NavIntE[a] * K[NavKi] * GPSdT;
+            NavIntE[a] = Decay1(NavIntE[a]);
+
+            Diff = (NavEp[a] - NavE[a]);
+            Diff = Limit(Diff, -256, 256);
+            NavD = Diff * K[NavKd] * GPSdTR;
+            NavD = Limit(NavD, -NAV_DIFF_LIMIT, NAV_DIFF_LIMIT);
+
+            NavEp[a] = NavE[a];
+
+            NavCorr[a] = (NavP + NavI + NavD ) * NavSensitivity;
+
+            NavCorr[a] = SlewLimit(NavCorrp[a], NavCorr[a], NAV_CORR_SLEW_LIMIT);
+            NavCorr[a] = Limit(NavCorr[a], -NAV_MAX_ROLL_PITCH, NAV_MAX_ROLL_PITCH);
+
+            NavCorrp[a] = NavCorr[a];
+        }
+
+        // Yaw
+        if ( F.AllowTurnToWP && !F.WayPointAchieved ) {
+            RelHeading = MakePi(WayHeading - Heading); // make +/- MilliPi
+            NavCorr[Yaw] = -(RelHeading * NavYCorrLimit) / HALFPI;
+            NavCorr[Yaw] = Limit(NavCorr[Yaw], -NavYCorrLimit, NavYCorrLimit); // gently!
+        } else
+            NavCorr[Yaw] = 0;
+
+#endif // NAV_WING    
+    } else {
+        // Neutral Zone - no GPS influence
+        NavCorr[Pitch] = DecayX(NavCorr[Pitch], 2);
+        NavCorr[Roll] = DecayX(NavCorr[Roll], 2);
+        NavCorr[Yaw] = 0;
+        NavIntE[Roll] = NavIntE[Pitch] = NavEp[Roll] = NavEp[Pitch] = 0;
+    }
+
+    F.NavComputed = true;
+
+} // Navigate
+
+void DoNavigation(void) {
+
+    F.NavigationActive = F.GPSValid && F.CompassValid && ( mSClock() > mS[NavActiveTime]);
+
+    if ( F.NavigationActive ) {
+    
+            F.LostModel = F.ForceFailsafe = false;
+
+        if ( !F.NavComputed )
+            switch ( NavState ) { // most case last - switches in C18 are IF chains not branch tables!
+                case Touchdown:
+                    Navigate(OriginLatitude, OriginLongitude);
+                    DoFailsafeLanding();
+                    break;
+                case Descending:
+                    Navigate( OriginLatitude, OriginLongitude );
+                    if ( F.ReturnHome || F.Navigate )
+#ifdef NAV_WING
+                    {
+                        // needs more thought - runway direction?
+                        DoFailsafeLanding();
+                    }
+#else
+                        if ( Altitude < LAND_M ) {
+                            mS[NavStateTimeout] = mSClock() + NAV_RTH_LAND_TIMEOUT_MS;
+                            NavState = Touchdown;
+                        } else
+                            DoFailsafeLanding();
+#endif // NAV_WING
+                    else
+                        AcquireHoldPosition();
+                    break;
+                case AtHome:
+                    Navigate(OriginLatitude, OriginLongitude);
+                    SetDesiredAltitude((int16)P[NavRTHAlt]);
+                    if ( F.ReturnHome || F.Navigate )
+                        if ( F.WayPointAchieved ) { // check still @ Home
+                            if ( F.UsingRTHAutoDescend && ( mSClock() > mS[NavStateTimeout] ) )
+                                NavState = Descending;
+                        } else
+                            NavState = ReturningHome;
+                    else
+                        AcquireHoldPosition();
+                    break;
+                case ReturningHome:
+                    Navigate(OriginLatitude, OriginLongitude);
+                    SetDesiredAltitude((int16)P[NavRTHAlt]);
+                    if ( F.ReturnHome || F.Navigate ) {
+                        if ( F.WayPointAchieved ) {
+                            mS[NavStateTimeout] = mSClock() + NavRTHTimeoutmS;
+                            NavState = AtHome;
+                        }
+                    } else
+                        AcquireHoldPosition();
+                    break;
+                case Loitering:
+                    Navigate(WPLatitude, WPLongitude);
+                    SetDesiredAltitude(WPAltitude);
+                    if ( F.Navigate ) {
+                        if ( F.WayPointAchieved && (mSClock() > mS[NavStateTimeout]) )
+                            if ( CurrWP == NoOfWayPoints ) {
+                                CurrWP = 1;
+                                NavState = ReturningHome;
+                            } else {
+                                GetWayPointPX(++CurrWP);
+                                NavState = Navigating;
+                            }
+                    } else
+                        AcquireHoldPosition();
+                    break;
+                case Navigating:
+                    Navigate(WPLatitude, WPLongitude);
+                    SetDesiredAltitude(WPAltitude);
+                    if ( F.Navigate ) {
+                        if ( F.WayPointAchieved ) {
+                            mS[NavStateTimeout] = mSClock() + WPLoiter;
+                            NavState = Loitering;
+                        }
+                    } else
+                        AcquireHoldPosition();
+                    break;
+                case HoldingStation:
+                    if ( F.AttitudeHold ) {
+                        if ( F.AcquireNewPosition && !( F.Ch5Active & F.UsingPositionHoldLock ) ) {
+                            F.AllowTurnToWP = SaveAllowTurnToWP;
+                            AcquireHoldPosition();
+#ifdef NAV_ACQUIRE_BEEPER
+                            if ( !F.BeeperInUse ) {
+                                mS[BeeperTimeout] = mSClock() + 500L;
+                                Beeper_ON;
+                            }
+#endif // NAV_ACQUIRE_BEEPER
+                        }
+                    } else
+                        F.AcquireNewPosition = true;
+
+                    Navigate(HoldLatitude, HoldLongitude);
+
+                    if ( F.NavValid && F.NearLevel )  // Origin must be valid for ANY navigation!
+                        if ( F.Navigate ) {
+                            GetWayPointPX(CurrWP); // resume from previous WP
+                            SetDesiredAltitude(WPAltitude);
+                            NavState = Navigating;
+                        } else
+                            if ( F.ReturnHome )
+                                NavState = ReturningHome;
+                    break;
+            } // switch NavState
+    } else
+        if ( F.ForceFailsafe && F.NewCommands )
+        {
+            F.AltHoldEnabled = F.AllowNavAltitudeHold = true;
+            F.LostModel = true;
+            DoFailsafeLanding();
+        }
+        else // kill nav correction immediately
+             NavCorr[Pitch] = NavCorr[Roll] = NavCorr[Yaw] = 0; // zzz
+
+    F.NewCommands = false;    // Navigate modifies Desired Roll, Pitch and Yaw values.
+
+} // DoNavigation
+
+void CheckFailsafeAbort(void) {
+    if ( mSClock() > mS[AbortTimeout] ) {
+        if ( F.Signal ) {
+            LEDGreen_ON;
+            mS[NavStateTimeout] = 0;
+            mS[FailsafeTimeout] = mSClock() + FAILSAFE_TIMEOUT_MS; // may be redundant?
+            NavState = HoldingStation;
+            FailState = MonitoringRx;
+        }
+    } else
+        mS[AbortTimeout] += ABORT_UPDATE_MS;
+} // CheckFailsafeAbort
+
+void DoPPMFailsafe(void) { // only relevant to PPM Rx or Quad NOT synchronising with Rx
+
+    if ( State == InFlight )
+        switch ( FailState ) { // FailStates { MonitoringRx, Aborting, Terminating, Terminated }
+            case Terminated: // Basic assumption is that aircraft is being flown over a safe area!
+                FailsafeHoldPosition();
+                DoFailsafeLanding();
+                break;
+            case Terminating:
+                FailsafeHoldPosition();
+                if ( Altitude < LAND_M ) {
+                    mS[NavStateTimeout] = mSClock() + NAV_RTH_LAND_TIMEOUT_MS;
+                    NavState = Touchdown;
+                    FailState = Terminated;
+                }
+                DoFailsafeLanding();
+                break;
+            case Aborting:
+                FailsafeHoldPosition();
+                F.AltHoldEnabled = true;
+                SetDesiredAltitude((int16)P[NavRTHAlt]);
+                if ( mSClock() > mS[NavStateTimeout] ) {
+                    F.LostModel = true;
+                    LEDGreen_OFF;
+                    LEDRed_ON;
+
+                    mS[NavStateTimeout] = mSClock() + NAV_RTH_LAND_TIMEOUT_MS;
+                    NavState = Descending;
+                    FailState = Terminating;
+                } else
+                    CheckFailsafeAbort();
+                break;
+            case MonitoringRx:
+                if ( mSClock() > mS[FailsafeTimeout] ) {
+                    // use last "good" throttle
+                    Stats[RCFailsafesS]++;
+                    if ( F.GPSValid && F.CompassValid )
+                        mS[NavStateTimeout] = mSClock() + ABORT_TIMEOUT_GPS_MS;
+                    else
+                        mS[NavStateTimeout] = mSClock() + ABORT_TIMEOUT_NO_GPS_MS;
+                    mS[AbortTimeout] = mSClock() + ABORT_UPDATE_MS;
+                    FailState = Aborting;
+                }
+                break;
+        } // Switch FailState
+    else
+        DesiredRoll = DesiredPitch = DesiredYaw = DesiredThrottle = 0;
+
+} // DoPPMFailsafe
+
+void UAVXNavCommand(void) {
+
+    static int16 b;
+    static uint8 c, d, csum;
+
+    c = RxChar();
+    LEDBlue_ON;
+
+    switch ( c ) {
+        case '0': // hello
+            TxChar(ACK);
+            break;
+        case '1': // write
+            csum = 0;
+            for ( b = 0; b < 256; b++) { // cannot write fast enough so buffer
+                d = RxChar();
+                csum ^= d;
+                BufferPX[b] = d;
+            }
+            if ( csum == (uint8)0 ) {
+                for ( b = 0; b < 256; b++)
+                    WritePX(NAV_ADDR_PX + b, BufferPX[b]);
+                TxChar(ACK);
+            } else
+                TxChar(NAK);
+
+            InitNavigation();
+
+            break;
+        case '2':
+            csum = 0;
+            for ( b = 0; b < 255; b++) {
+                d = ReadPX(NAV_ADDR_PX + b);
+                csum ^= d;
+                BufferPX[b] = d;
+            }
+            BufferPX[255] = csum;
+            for ( b = 0; b < 256; b++)
+                TxChar(BufferPX[b]);
+            TxChar(ACK);
+            break;
+        case '3':
+            csum = 0;
+            for ( b = 0; b < 63; b++) {
+                d = ReadPX(STATS_ADDR_PX + b);
+                csum ^= d;
+                BufferPX[b] = d;
+            }
+            BufferPX[63] = csum;
+            for ( b = 0; b < 64; b++)
+                TxChar(BufferPX[b]);
+            TxChar(ACK);
+            break;
+        default:
+            break;
+    } // switch
+
+    WritePXImagefile();
+    LEDBlue_OFF;
+
+} // UAVXNavCommand
+
+void GetWayPointPX(int8 wp) {
+    static uint16 w;
+
+    if ( wp > NoOfWayPoints )
+        CurrWP = wp = 0;
+    if ( wp == 0 ) { // force to Origin
+        WPLatitude = OriginLatitude;
+        WPLongitude = OriginLongitude;
+        WPAltitude = (int16)P[NavRTHAlt];
+        WPLoiter = 30000; // mS
+    } else {
+        w = NAV_WP_START + (wp-1) * WAYPOINT_REC_SIZE;
+        WPLatitude = Read32PX(w + 0);
+        WPLongitude = Read32PX(w + 4);
+        WPAltitude = Read16PX(w + 8);
+
+#ifdef NAV_ENFORCE_ALTITUDE_CEILING
+        if ( WPAltitude > NAV_CEILING )
+            WPAltitude = NAV_CEILING;
+#endif // NAV_ENFORCE_ALTITUDE_CEILING
+        WPLoiter = (int16)ReadPX(w + 10) * 1000L; // mS
+    }
+
+    F.WayPointCentred =  F.WayPointAchieved = false;
+
+} // GetWaypointPX
+
+void InitNavigation(void) {
+    static uint8 i;
+
+    HoldLatitude = HoldLongitude = WayHeading = 0;
+
+    for ( i = 0; i < (uint8)3; i++ )
+        NavEp[i] = NavIntE[i] = NavCorr[i] = NavCorrp[i] = 0;
+
+    NavState = HoldingStation;
+    AttitudeHoldResetCount = 0;
+    CurrMaxRollPitch = 0;
+    F.WayPointAchieved = F.WayPointCentred = false;
+    F.NavComputed = false;
+
+    if ( ReadPX(NAV_NO_WP) <= 0 ) {
+        NavProximityRadius = ConvertMToGPS(NAV_PROXIMITY_RADIUS);
+        NavProximityAltitude = NAV_PROXIMITY_ALTITUDE * 10L; // Decimetres
+    } else {
+        // need minimum values in UAVXNav?
+        NavProximityRadius = ConvertMToGPS(ReadPX(NAV_PROX_RADIUS));
+        NavProximityAltitude = ReadPX(NAV_PROX_ALT) * 10L; // Decimetres
+    }
+
+    NoOfWayPoints = ReadPX(NAV_NO_WP);
+
+    if ( NoOfWayPoints <= 0 )
+        CurrWP = 0;
+    else
+        CurrWP = 1;
+    GetWayPointPX(0);
+
+} // InitNavigation
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/baro.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,613 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+// Barometers Freescale TI ADC and Bosch BMP085 3.8MHz, Bosch SMD500 400KHz
+
+#define BARO_MIN_CLIMB          150.0    // M minimum available barometer climb from origin
+#define BARO_MIN_DESCENT        -50.0    //M minimum available barometer descent from origin
+
+void GetBaroAltitude(void);
+void InitBarometer(void);
+
+void ShowBaroType(void);
+void BaroTest(void);
+
+#define BaroROCFilter HardFilter
+
+uint16   BaroPressure, BaroTemperature;
+boolean  AcquiringPressure;
+int16    BaroOffsetDAC;
+
+#define BARO_BUFF_SIZE              4
+
+struct {
+    uint8 Head, Tail;
+    int24 B[BARO_BUFF_SIZE];
+} BaroQ;
+
+int32    OriginBaroPressure, CompBaroPressure;
+real32   BaroRelAltitude, BaroRelAltitudeP;
+i16u     BaroVal;
+int8     BaroType;
+int16    BaroClimbAvailable, BaroDescentAvailable;
+int16    AltitudeUpdateRate;
+int8     BaroRetries;
+
+real32   FakeBaroRelAltitude;
+int8     SimulateCycles = 0;
+
+void ShowBaroType(void) {
+    switch ( BaroType ) {
+        case BaroMPX4115:
+            TxString("MPX4115\r\n");
+            break;
+        case BaroSMD500:
+            TxString("SMD500\r\n");
+            break;
+        case BaroBMP085:
+            TxString("BMP085\r\n");
+            break;
+        case BaroUnknown:
+            TxString("None\r\n");
+            break;
+        default:
+            break;
+    }
+} // ShowBaro
+
+void BaroTest(void) {
+    TxString("\r\nAltitude test\r\n");
+
+    TxString("Initialising\r\n");
+
+    InitBarometer();
+
+    while ( F.BaroAltitudeValid && ! F.NewBaroValue )
+        GetBaroAltitude();
+
+    TxString("\r\nType:\t");
+    ShowBaroType();
+
+    TxString("Init Retries:\t");
+    TxVal32((int32)BaroRetries - 2, 0, ' '); // always minimum of 2
+    if ( BaroRetries >= BARO_INIT_RETRIES )
+        TxString(" FAILED Init.\r\n");
+    else
+        TxNextLine();
+
+    if ( BaroType == BaroMPX4115 ) {
+        TxString("Range   :\t");
+        TxVal32((int32) BaroDescentAvailable * 10.0, 1, ' ');
+        TxString("-> ");
+        TxVal32((int32) BaroClimbAvailable * 10.0, 1, 'M');
+        TxString(" {Offset ");
+        TxVal32((int32)BaroOffsetDAC, 0,'}');
+        if (( BaroClimbAvailable < BARO_MIN_CLIMB ) || (BaroDescentAvailable > BARO_MIN_DESCENT))
+            TxString(" Bad climb or descent range - offset adjustment?");
+        TxNextLine();
+    }
+
+    if ( !F.BaroAltitudeValid ) goto BAerror;
+
+    while ( !F.NewBaroValue )
+        GetBaroAltitude();
+    F.NewBaroValue = false;
+
+    TxString("Alt.:     \t");
+    TxVal32(BaroRelAltitude * 10.0, 1, ' ');
+    TxString("M\r\n");
+
+    TxString("\r\nR.Finder: \t");
+    if ( F.RangefinderAltitudeValid ) {
+        GetRangefinderAltitude();
+        TxVal32(RangefinderAltitude * 100.0, 2, ' ');
+        TxString("M\r\n");
+    } else
+        TxString("no rangefinder\r\n");
+
+    TxString("\r\nAmbient :\t");
+    TxVal32((int32)AmbientTemperature.i16, 1, ' ');
+    TxString("C\r\n");
+
+    return;
+BAerror:
+    TxString("FAIL\r\n");
+} // BaroTest
+
+void GetBaroAltitude(void) {
+    static real32 Temp, AltChange;
+
+    if ( BaroType == BaroMPX4115 )
+        GetFreescaleBaroAltitude();
+    else
+        GetBoschBaroAltitude();
+
+    if ( F.NewBaroValue ) {
+#ifdef SIMULATE
+        if ( State == InFlight ) {
+            if ( ++SimulateCycles >= AltitudeUpdateRate ) {
+                FakeBaroRelAltitude += ( DesiredThrottle - CruiseThrottle ) + Comp[Alt];
+                if ( FakeBaroRelAltitude < -5.0 )
+                    FakeBaroRelAltitude = 0.0;
+
+                SimulateCycles = 0;
+
+                ROC = FakeBaroRelAltitude - BaroRelAltitudeP;
+                BaroRelAltitudeP = FakeBaroRelAltitude;
+            }
+            BaroRelAltitude = FakeBaroRelAltitude;
+        }
+#else
+
+        AltChange = BaroRelAltitude - BaroRelAltitudeP;
+        Temp = AltChange * AltitudeUpdateRate;
+
+        if ( fabs( Temp ) > BARO_SANITY_CHECK_MPS ) {
+            BaroRelAltitude = BaroRelAltitudeP;    // use previous value
+            Temp = 0;
+            Stats[BaroFailS]++;
+        }
+
+        Temp = Limit( Temp , -BARO_SANITY_CHECK_MPS, BARO_SANITY_CHECK_MPS );
+        ROC = ROC * 0.9 + Temp * 0.1;
+        BaroRelAltitudeP = BaroRelAltitude;
+
+#endif // SIMULATE
+
+        if ( State == InFlight ) {
+            if ( ROC > Stats[MaxROCS] )
+                Stats[MaxROCS] = ROC;
+            else
+                if ( ROC < Stats[MinROCS] )
+                    Stats[MinROCS] = ROC;
+
+            if ( BaroRelAltitude > Stats[BaroRelAltitudeS] )
+                Stats[BaroRelAltitudeS] = BaroRelAltitude;
+        }
+    }
+
+} // GetBaroAltitude
+
+void InitBarometer(void) {
+    BaroRelAltitude = BaroRelAltitudeP = CompBaroPressure = OriginBaroPressure = 0;
+    BaroType = BaroUnknown;
+
+    Comp[Alt] = AltDiffSum = AltDSum = 0;
+    F.BaroAltitudeValid= true; // optimistic
+
+    if ( IsFreescaleBaroActive() )
+        InitFreescaleBarometer();
+    else
+        if ( IsBoschBaroActive() )
+            InitBoschBarometer();
+        else {
+            F.BaroAltitudeValid = F.HoldingAlt = false;
+            Stats[BaroFailS]++;
+        }
+} // InitBarometer
+
+// -----------------------------------------------------------
+
+// Freescale ex Motorola MPX4115 Barometer with ADS7823 12bit ADC
+
+void SetFreescaleMCP4725(int16);
+void SetFreescaleOffset(void);
+void ReadFreescaleBaro(void);
+real32 FreescaleToDM(int24);
+void GetFreescaleBaroAltitude(void);
+boolean IsFreescaleBaroActive(void);
+void InitFreescaleBarometer(void);
+
+void SetFreescaleMCP4725(int16 d) {
+    static i16u dd;
+    static uint8 r;
+
+    dd.u16 = d << 4;                            // left align
+
+    I2CBARO.start();
+    r = I2CBARO.write(MCP4725_WR) != I2C_ACK;
+    r = I2CBARO.write(MCP4725_CMD) != I2C_ACK;
+    r = I2CBARO.write(dd.b1) != I2C_ACK;
+    r = I2CBARO.write(dd.b0) != I2C_ACK;
+    I2CBARO.stop();
+
+} // SetFreescaleMCP4725
+
+void SetFreescaleOffset(void) {
+    // Steve Westerfeld
+    // 470 Ohm, 1uF RC 0.47mS use 2mS for settling?
+
+    TxString("\r\nOffset \tPressure\r\n");
+
+    BaroOffsetDAC = MCP4725_MAX;
+
+    SetFreescaleMCP4725(BaroOffsetDAC);
+
+    Delay1mS(20);                               // initial settling
+    ReadFreescaleBaro();
+
+    while ( (BaroVal.u16 < (uint16)(((uint24)ADS7823_MAX*4L*7L)/10L) )
+            && (BaroOffsetDAC > 20) ) {         // first loop gets close
+        BaroOffsetDAC -= 20;                    // approach at 20 steps out of 4095
+        SetFreescaleMCP4725(BaroOffsetDAC);
+        Delay1mS(20);
+        ReadFreescaleBaro();
+        TxVal32(BaroOffsetDAC,0,HT);
+        TxVal32(BaroVal.u16,0,' ');
+        TxNextLine();
+        LEDYellow_TOG;
+    }
+
+    BaroOffsetDAC += 20;                        // move back up to come at it a little slower
+    SetFreescaleMCP4725(BaroOffsetDAC);
+    Delay1mS(100);
+    ReadFreescaleBaro();
+
+    while ( (BaroVal.u16 < (uint16)(((uint24)ADS7823_MAX*4L*3L)/4L) ) && (BaroOffsetDAC > 2) ) {
+        BaroOffsetDAC -= 2;
+        SetFreescaleMCP4725(BaroOffsetDAC);
+        Delay1mS(10);
+        ReadFreescaleBaro();
+        TxVal32(BaroOffsetDAC,0,HT);
+        TxVal32(BaroVal.u16,0,' ');
+        TxNextLine();
+        LEDYellow_TOG;
+    }
+
+    Delay1mS(200); // wait for caps to settle
+    F.BaroAltitudeValid = BaroOffsetDAC > 0;
+
+} // SetFreescaleOffset
+
+void ReadFreescaleBaro(void) {
+    static char B[8];
+    static i16u B0, B1, B2, B3;
+
+    mS[BaroUpdate] = mSClock() + ADS7823_TIME_MS;
+
+    I2CBARO.start();  // start conversion
+
+    if ( I2CBARO.write(ADS7823_WR) != I2C_ACK ) goto FSError;
+    if ( I2CBARO.write(ADS7823_CMD) != I2C_ACK ) goto FSError;
+
+    I2CBARO.read(ADS7823_RD, B, 8);  // read block of 4 baro samples
+
+    B0.b0 = B[1];
+    B0.b1 = B[0];
+    B1.b0 = B[3];
+    B1.b1 = B[2];
+    B2.b0 = B[5];
+    B2.b1 = B[4];
+    B3.b0 = B[7];
+    B3.b1 = B[6];
+
+    BaroVal.u16 = (uint16)16380 - ( B0.u16 + B1.u16 + B2.u16 + B3.u16 );
+
+    F.BaroAltitudeValid = true;
+
+    return;
+
+FSError:
+    I2CBARO.stop();
+
+    F.BaroAltitudeValid = F.HoldingAlt = false;
+    if ( State == InFlight ) {
+        Stats[BaroFailS]++;
+        F.BaroFailure = true;
+    }
+    return;
+} // ReadFreescaleBaro
+
+real32 FreescaleToDM(int24 p) { // decreasing pressure is increase in altitude negate and rescale to metre altitude
+    return( -( (real32)p * 0.8 ) / (real32)P[BaroScale] );
+}  // FreescaleToDM
+
+void GetFreescaleBaroAltitude(void) {
+    static int24 BaroPressure;
+
+    if ( mSClock() >= mS[BaroUpdate] ) {
+        ReadFreescaleBaro();
+        if ( F.BaroAltitudeValid ) {
+            BaroPressure = (int24)BaroVal.u16; // sum of 4 samples
+
+            BaroRelAltitude = FreescaleToDM(BaroPressure - OriginBaroPressure);
+
+            F.NewBaroValue = F.BaroAltitudeValid;
+        }
+    }
+
+} // GetFreescaleBaroAltitude
+
+boolean IsFreescaleBaroActive(void) { // check for Freescale Barometer
+
+    I2CBARO.start();
+    if ( I2CBARO.write(ADS7823_ID) != I2C_ACK ) goto FreescaleInactive;
+
+    BaroType = BaroMPX4115;
+    I2CBARO.stop();
+    
+    TrackMinI2CRate(400000);
+
+    return(true);
+
+FreescaleInactive:
+    I2CBARO.stop();
+    return(false);
+
+} // IsFreescaleBaroActive
+
+void InitFreescaleBarometer(void) {
+    static int16 BaroOriginAltitude, MinAltitude;
+    real32 Error;
+    static int24 BaroPressureP;
+
+    AltitudeUpdateRate = 1000L/ADS7823_TIME_MS;
+
+    BaroTemperature = 0;
+    Error = ( (int16)P[BaroScale] * 20 ) / 16;  // 0.2M
+    BaroPressure =  0;
+
+    BaroRetries = 0;
+    do {
+        BaroPressureP = BaroPressure;
+
+        SetFreescaleOffset();
+
+        while ( mSClock() < mS[BaroUpdate] ) {};
+        ReadFreescaleBaro();
+        BaroPressure = (int24)BaroVal.u16;
+    } while ( ( ++BaroRetries < BARO_INIT_RETRIES )
+              && ( abs((int16)(BaroPressure - BaroPressureP)) > Error ) );
+
+    F.BaroAltitudeValid = BaroRetries < BARO_INIT_RETRIES;
+
+    OriginBaroPressure = BaroPressure;
+
+    BaroRelAltitudeP = BaroRelAltitude = 0.0;
+
+    MinAltitude = FreescaleToDM((int24)ADS7823_MAX*4);
+    BaroOriginAltitude = FreescaleToDM(OriginBaroPressure);
+    BaroDescentAvailable = MinAltitude - BaroOriginAltitude;
+    BaroClimbAvailable = -BaroOriginAltitude;
+
+    //F.BaroAltitudeValid &= (( BaroClimbAvailable >= BARO_MIN_CLIMB )
+    // && (BaroDescentAvailable <= BARO_MIN_DESCENT));
+
+#ifdef SIMULATE
+    FakeBaroRelAltitude = 0;
+#endif // SIMULATE
+
+} // InitFreescaleBarometer
+
+// -----------------------------------------------------------
+
+// Bosch SMD500 and BMP085 Barometers
+
+void StartBoschBaroADC(boolean);
+int24 CompensatedBoschPressure(uint16, uint16);
+
+void GetBoschBaroAltitude(void);
+boolean IsBoschBaroActive(void);
+void InitBoschBarometer(void);
+
+// SMD500 9.5mS (T) 34mS (P)
+// BMP085 4.5mS (T) 25.5mS (P) OSRS=3
+#define BOSCH_TEMP_TIME_MS            11    // 10 increase to make P+T acq time ~50mS
+//#define BMP085_PRESS_TIME_MS         26
+//#define SMD500_PRESS_TIME_MS         34
+#define BOSCH_PRESS_TIME_MS            38
+#define BOSCH_PRESS_TEMP_TIME_MS    50    // pressure and temp time + overheads     
+
+void StartBoschBaroADC(boolean ReadPressure) {
+    static uint8 TempOrPress;
+
+    if ( ReadPressure ) {
+        TempOrPress = BOSCH_PRESS;
+        mS[BaroUpdate] = mSClock() + BOSCH_PRESS_TIME_MS;
+    } else {
+        mS[BaroUpdate] = mSClock() + BOSCH_TEMP_TIME_MS;
+        if ( BaroType == BaroBMP085 )
+            TempOrPress = BOSCH_TEMP_BMP085;
+        else
+            TempOrPress = BOSCH_TEMP_SMD500;
+    }
+
+    I2CBARO.start();
+    if ( I2CBARO.write(BOSCH_ID) != I2C_ACK ) goto SBerror;
+
+    // access control register, start measurement
+    if ( I2CBARO.write(BOSCH_CTL) != I2C_ACK ) goto SBerror;
+
+    // select 32kHz input, measure temperature
+    if ( I2CBARO.write(TempOrPress) != I2C_ACK ) goto SBerror;
+    I2CBARO.stop();
+
+    F.BaroAltitudeValid = true;
+    return;
+
+SBerror:
+    I2CBARO.stop();
+    F.BaroAltitudeValid = F.HoldingAlt = false;
+    return;
+} // StartBoschBaroADC
+
+void ReadBoschBaro(void) {
+    // Possible I2C protocol error - split read of ADC
+    I2CBARO.start();
+    if ( I2CBARO.write(BOSCH_ID) != I2C_ACK ) goto RVerror;
+    if ( I2CBARO.write(BOSCH_ADC_MSB) != I2C_ACK ) goto RVerror;
+    I2CBARO.start();    // restart
+    if ( I2CBARO.write(BOSCH_ID+1) != I2C_ACK ) goto RVerror;
+    BaroVal.b1 = I2CBARO.read(I2C_NACK);
+    I2CBARO.stop();
+
+    I2CBARO.start();
+    if ( I2CBARO.write(BOSCH_ID) != I2C_ACK ) goto RVerror;
+    if ( I2CBARO.write(BOSCH_ADC_LSB) != I2C_ACK ) goto RVerror;
+    I2CBARO.start();    // restart
+    if ( I2CBARO.write(BOSCH_ID+1) != I2C_ACK ) goto RVerror;
+    BaroVal.b0 = I2CBARO.read(I2C_NACK);
+    I2CBARO.stop();
+
+    F.BaroAltitudeValid = true;
+    return;
+
+RVerror:
+    I2CBARO.stop();
+
+    F.BaroAltitudeValid = F.HoldingAlt = false;
+    if ( State == InFlight ) {
+        Stats[BaroFailS]++;
+        F.BaroFailure = true;
+    }
+    return;
+} // ReadBoschBaro
+
+#define BOSCH_BMP085_TEMP_COEFF        62L
+#define BOSCH_SMD500_TEMP_COEFF        50L
+
+int24 CompensatedBoschPressure(uint16 BaroPress, uint16 BaroTemp) {
+    static int24 BaroTempComp;
+
+    if ( BaroType == BaroBMP085 )
+        BaroTempComp = (BaroTemp * BOSCH_BMP085_TEMP_COEFF + 64L) >> 7;
+    else
+        BaroTempComp = (BaroTemp * BOSCH_SMD500_TEMP_COEFF + 8L) >> 4;
+
+    return ((int24)BaroPress + BaroTempComp - OriginBaroPressure);
+
+} // CompensatedBoschPressure
+
+void GetBoschBaroAltitude(void) {
+    static int24 Temp;
+
+    if ( mSClock() >= mS[BaroUpdate] ) {
+        ReadBoschBaro();
+        if ( F.BaroAltitudeValid )
+            if ( AcquiringPressure ) {
+                BaroPressure = (int24)BaroVal.u16;
+                AcquiringPressure = false;
+            } else {
+                BaroTemperature = (int24)BaroVal.u16;
+                AcquiringPressure = true;
+
+                Temp = CompensatedBoschPressure(BaroPressure, BaroTemperature);
+                CompBaroPressure -= BaroQ.B[BaroQ.Head];
+                BaroQ.B[BaroQ.Head] = Temp;
+                CompBaroPressure += Temp;
+                BaroQ.Head = (BaroQ.Head + 1) & (BARO_BUFF_SIZE -1);
+
+                // Pressure queue has 4 entries corresponding to an average delay at 20Hz of 0.1Sec
+                // decreasing pressure is increase in altitude negate and rescale to decimetre altitude
+
+                BaroRelAltitude = - ( (real32)CompBaroPressure * (real32)P[BaroScale] ) / 1280.0;
+
+                F.NewBaroValue = F.BaroAltitudeValid;
+            }
+        else {
+            AcquiringPressure = true;
+            Stats[BaroFailS]++;
+        }
+
+        StartBoschBaroADC(AcquiringPressure);
+    }
+} // GetBoschBaroAltitude
+
+boolean IsBoschBaroActive(void) { // check for Bosch Barometers
+    static uint8 r;
+
+    I2CBARO.start();
+    if ( I2CBARO.write(BOSCH_ID) != I2C_ACK ) goto BoschInactive;
+    if ( I2CBARO.write(BOSCH_TYPE) != I2C_ACK ) goto BoschInactive;
+    I2CBARO.start();    // restart
+    if ( I2CBARO.write(BOSCH_ID+1) != I2C_ACK ) goto BoschInactive;
+    r = I2CBARO.read(I2C_NACK);
+    I2CBARO.stop();
+
+    if (r == BOSCH_ID_BMP085 )
+        BaroType = BaroBMP085;
+    else
+        BaroType = BaroSMD500;
+        
+    TrackMinI2CRate(400000);
+
+    return(true);
+
+BoschInactive:
+    return(false);
+
+} // IsBoschBaroActive
+
+void InitBoschBarometer(void) {
+    int8 s;
+    int24 Temp, CompBaroPressureP;
+
+    AltitudeUpdateRate = 1000L / BOSCH_PRESS_TEMP_TIME_MS;
+
+    F.NewBaroValue = false;
+    CompBaroPressure = 0;
+
+    TxString("Temp. \tPressure\r\n");
+
+    BaroRetries = 0;
+    do { // occasional I2C misread of Temperature so keep doing it until the Origin is stable!!
+        CompBaroPressureP = CompBaroPressure;
+        CompBaroPressure = BaroQ.Head = 0;
+
+        AcquiringPressure = true;
+        StartBoschBaroADC(AcquiringPressure); // Pressure
+
+        for ( s = 0; s < 4; s++ ) {
+            while ( mSClock() < mS[BaroUpdate] );
+            ReadBoschBaro(); // Pressure
+            BaroPressure = BaroVal.u16;
+
+            AcquiringPressure = !AcquiringPressure;
+            StartBoschBaroADC(AcquiringPressure); // Temperature
+            while ( mSClock() < mS[BaroUpdate] );
+            ReadBoschBaro();
+            BaroTemperature = BaroVal.u16;
+
+            TxVal32(BaroTemperature,0,HT);
+            TxVal32(BaroPressure,0,0);
+            TxNextLine();
+
+            Temp = CompensatedBoschPressure(BaroPressure, BaroTemperature);
+            BaroQ.B[s] = Temp;
+            CompBaroPressure += Temp;
+
+            AcquiringPressure = !AcquiringPressure;
+            StartBoschBaroADC(AcquiringPressure);
+        }
+
+    } while ( ( ++BaroRetries < BARO_INIT_RETRIES ) && ( abs(CompBaroPressure - CompBaroPressureP) > 12 ) ); // stable within ~0.5M
+
+    OriginBaroPressure = SRS32(CompBaroPressure, 2);
+
+    F.BaroAltitudeValid = BaroRetries < BARO_INIT_RETRIES;
+    BaroRelAltitudeP = BaroRelAltitude = 0.0;
+
+#ifdef SIMULATE
+    FakeBaroRelAltitude = 0.0;
+#endif // SIMULATE
+
+} // InitBoschBarometer
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/compass.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,525 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+// Local magnetic declination not included
+// http://www.ngdc.noaa.gov/geomagmodels/Declination.jsp
+
+
+void ReadCompass(void);
+void GetHeading(void);
+void CalibrateCompass(void);
+void ShowCompassType(void);
+void DoCompassTest(void);
+void InitCompass(void);
+
+MagStruct Mag[3] = {{ 0,0 },{ 0,0 },{ 0,0 }};
+real32 MagDeviation, CompassOffset;
+real32 MagHeading, Heading, Headingp, FakeHeading;
+real32 HeadingSin, HeadingCos;
+uint8 CompassType;
+
+void ReadCompass(void) {
+    switch ( CompassType ) {
+        case HMC5843:
+            ReadHMC5843();
+            break;
+        case HMC6352:
+            ReadHMC6352();
+            break;
+        default:
+            Heading = 0;
+            break;
+    } // switch
+
+} // ReadCompass
+
+void CalibrateCompass(void) {
+    switch ( CompassType ) {
+        case HMC5843:
+            CalibrateHMC5843();
+            break;
+        case HMC6352:
+            CalibrateHMC6352();
+            break;
+        default:
+            break;
+    } // switch
+} // CalibrateCompass
+
+void ShowCompassType(void) {
+ switch ( CompassType ) {
+        case HMC5843:
+             TxString("HMC5843");
+            break;
+        case HMC6352:
+            TxString("HMC6352");
+            break;
+        default:
+            break;
+    }
+ } // ShowCompassType
+
+void DoCompassTest(void) {
+    switch ( CompassType ) {
+        case HMC5843:
+            DoHMC5843Test();
+            break;
+        case HMC6352:
+            DoHMC6352Test();
+            break;
+        default:
+            TxString("\r\nCompass test\r\nCompass not detected?\r\n");
+            break;
+    } // switch
+} // DoCompassTest
+
+void GetHeading(void) {
+
+    const real32 CompassA = COMPASS_UPDATE_S / ( OneOnTwoPiCompassF + COMPASS_UPDATE_S );
+
+    ReadCompass();
+
+    Heading = Make2Pi( MagHeading - MagDeviation - CompassOffset );
+    if ( fabs(Heading - Headingp ) > PI )
+        Headingp = Heading;
+
+    Heading = Headingp + (Heading - Headingp) * CompassA;
+    Headingp = Heading;
+
+#ifdef SIMULATE
+#if ( defined AILERON | defined ELEVON )
+    if ( State == InFlight )
+        FakeHeading -= FakeDesiredRoll/5 + FakeDesiredYaw/5;
+#else
+    if ( State == InFlight ) {
+        if ( Abs(FakeDesiredYaw) > 5 )
+            FakeHeading -= FakeDesiredYaw/5;
+    }
+
+    FakeHeading = Make2Pi((int16)FakeHeading);
+    Heading = FakeHeading;
+#endif // AILERON | ELEVON
+#endif // SIMULATE 
+} // GetHeading
+
+void InitCompass(void) {
+    if ( IsHMC5843Active() )
+        CompassType = HMC5843;
+    else
+        if ( HMC6352Active() )
+            CompassType = HMC6352;
+        else {
+            CompassType = NoCompass;
+            F.CompassValid = false;
+        }
+
+    switch ( CompassType ) {
+        case HMC5843:
+            InitHMC5843();
+            break;
+        case HMC6352:
+            InitHMC6352();
+            break;
+        default:
+            MagHeading = 0;
+    } // switch
+
+    ReadCompass();
+    mS[CompassUpdate] = mSClock();
+    Heading = Headingp = Make2Pi( MagHeading - MagDeviation - CompassOffset );
+
+} // InitCompass
+
+//________________________________________________________________________________________
+
+// HMC5843 3 Axis Magnetometer
+
+void ReadHMC5843(void);
+void GetHMC5843Parameters(void);
+void DoHMC5843Test(void);
+void CalibrateHMC5843(void);
+void InitHMC5843(void);
+boolean HMC5843Active(void);
+
+void ReadHMC5843(void) {
+    static char b[6];
+    static i16u X, Y, Z;
+    static uint8 r;
+    static real32 mx, my;
+    static real32 CRoll, SRoll, CPitch, SPitch;
+
+    I2CCOMPASS.start();
+    r = I2CCOMPASS.write(HMC5843_ID);
+    r = I2CCOMPASS.write(0x03); // point to data
+    I2CCOMPASS.stop();
+
+    I2CCOMPASS.read(HMC5843_ID, b, 6);
+
+    X.b1 = b[0];
+    X.b0 = b[1];
+    Y.b1 = b[2];
+    Y.b0  =b[3];
+    Z.b1 = b[4];
+    Z.b0 = b[5];
+
+    if ( F.Using9DOF ) { // SparkFun/QuadroUFO 9DOF Breakout pins  front edge components up
+        Mag[BF].V = X.i16;
+        Mag[LR].V = -Y.i16;
+        Mag[UD].V = -Z.i16;
+    } else { // SparkFun Magnetometer Breakout pins  right edge components up
+        Mag[BF].V = -X.i16;
+        Mag[LR].V = Y.i16;
+        Mag[UD].V = -Z.i16;
+    }
+
+    CRoll = cos(Angle[Roll]);
+    SRoll = sin(Angle[Roll]);
+    CPitch = cos(Angle[Pitch]);
+    SPitch = sin(Angle[Pitch]);
+
+    mx = (Mag[BF].V-Mag[BF].Offset) * CPitch + (Mag[LR].V-Mag[LR].Offset) * SRoll * SPitch + (Mag[UD].V-Mag[UD].Offset) * CRoll * SPitch;
+    my =  (Mag[LR].V-Mag[LR].Offset) * CRoll - (Mag[UD].V-Mag[UD].Offset) * SRoll;
+
+    // Magnetic Heading
+    MagHeading = MakePi(atan2( -my, mx ));
+
+    F.CompassValid = true;
+    return;
+
+} // ReadHMC5843
+
+void CalibrateHMC5843(void) {
+
+} // DoHMC5843Test
+
+void DoHMC5843Test(void) {
+    TxString("\r\nCompass test (HMC5843)\r\n\r\n");
+
+    ReadHMC5843();
+
+    TxString("Mag:\t");
+    TxVal32(Mag[LR].V, 0, HT);
+    TxVal32(Mag[BF].V, 0, HT);
+    TxVal32(Mag[UD].V, 0, HT);
+    TxNextLine();
+    TxNextLine();
+
+    TxVal32(MagHeading * RADDEG * 10.0, 1, 0);
+    TxString(" deg (Magnetic)\r\n");
+    
+    Heading = Headingp = Make2Pi( MagHeading - MagDeviation - CompassOffset );
+    TxVal32(Heading * RADDEG * 10.0, 1, 0);
+    TxString(" deg (True)\r\n");
+} // DoHMC5843Test
+
+void InitHMC5843(void) {
+    static uint8 r;
+
+    I2CCOMPASS.start();
+    r = I2CCOMPASS.write(HMC5843_ID);
+    r = I2CCOMPASS.write(0x02);
+    r = I2CCOMPASS.write(0x00);   // Set continuous mode (default to 10Hz)
+    I2CCOMPASS.stop();
+
+    Delay1mS(50);
+
+} // InitHMC5843Magnetometer
+
+boolean IsHMC5843Active(void) {
+    I2CCOMPASS.start();
+    F.CompassValid = !(I2CCOMPASS.write(HMC5843_ID) != I2C_ACK);
+    I2CCOMPASS.stop();
+    
+    if ( F.CompassValid )
+        TrackMinI2CRate(400000);
+
+    return ( F.CompassValid );
+
+} // IsHMC5843Active
+
+//________________________________________________________________________________________
+
+// HMC6352 Compass
+
+void ReadHMC6352(void);
+uint8 WriteByteHMC6352(uint8);
+void GetHMC6352Parameters(void);
+void DoHMC6352Test(void);
+void CalibrateHMC6352(void);
+void InitHMC6352(void);
+boolean IsHMC6352Active(void);
+
+void ReadHMC6352(void) {
+    static i16u v;
+
+    I2CCOMPASS.start();
+    F.CompassMissRead = I2CCOMPASS.write(HMC6352_ID + 1) != I2C_ACK;
+    v.b1 = I2CCOMPASS.read(I2C_ACK);
+    v.b0 = I2CCOMPASS.read(I2C_NACK);
+    I2CCOMPASS.stop();
+
+    MagHeading = Make2Pi( ((real32)v.i16 * PI) / 1800.0 - CompassOffset ); // Radians
+} // ReadHMC6352
+
+uint8 WriteByteHMC6352(uint8 d) {
+    I2CCOMPASS.start();
+    if ( I2CCOMPASS.write(HMC6352_ID) != I2C_ACK ) goto WError;
+    if ( I2CCOMPASS.write(d) != I2C_ACK ) goto WError;
+    I2CCOMPASS.stop();
+
+    return( I2C_ACK );
+WError:
+    I2CCOMPASS.stop();
+    return ( I2C_NACK );
+} // WriteByteHMC6352
+
+char CP[9];
+
+#define TEST_COMP_OPMODE 0x70    // standby mode to reliably read EEPROM
+
+void GetHMC6352Parameters(void) {
+    uint8 r;
+
+    I2CCOMPASS.start();
+    if ( I2CCOMPASS.write(HMC6352_ID) != I2C_ACK ) goto CTerror;
+    if ( I2CCOMPASS.write('G')  != I2C_ACK ) goto CTerror;
+    if ( I2CCOMPASS.write(0x74) != I2C_ACK ) goto CTerror;
+    if ( I2CCOMPASS.write(TEST_COMP_OPMODE) != I2C_ACK ) goto CTerror;
+    I2CCOMPASS.stop();
+
+    Delay1mS(20);
+
+    for (r = 0; r <= (uint8)8; r++) { // must have this timing - not block read!
+
+        I2CCOMPASS.start();
+        if ( I2CCOMPASS.write(HMC6352_ID) != I2C_ACK ) goto CTerror;
+        if ( I2CCOMPASS.write('r')  != I2C_ACK ) goto CTerror;
+        if ( I2CCOMPASS.write(r)  != I2C_ACK ) goto CTerror;
+        I2CCOMPASS.stop();
+
+        Delay1mS(10);
+
+        I2CCOMPASS.start();
+        if ( I2CCOMPASS.write(HMC6352_ID+1) != I2C_ACK ) goto CTerror;
+        CP[r] = I2CCOMPASS.read(I2C_NACK);
+        I2CCOMPASS.stop();
+
+        Delay1mS(10);
+    }
+
+    return;
+
+CTerror:
+    I2CCOMPASS.stop();
+    TxString("FAIL\r\n");
+
+} // GetHMC6352Parameters
+
+void DoHMC6352Test(void) {
+    static real32 Temp;
+
+    TxString("\r\nCompass test (HMC6352)\r\n");
+
+    I2CCOMPASS.start();
+    if ( I2CCOMPASS.write(HMC6352_ID) != I2C_ACK ) goto CTerror;
+    if ( I2CCOMPASS.write('G')  != I2C_ACK ) goto CTerror;
+    if ( I2CCOMPASS.write(0x74) != I2C_ACK ) goto CTerror;
+    if ( I2CCOMPASS.write(TEST_COMP_OPMODE) != I2C_ACK ) goto CTerror;
+    I2CCOMPASS.stop();
+
+    Delay1mS(1);
+
+    //  I2CCOMPASS.start(); // Do Set/Reset now
+    if ( WriteByteHMC6352('O')  != I2C_ACK ) goto CTerror;
+
+    Delay1mS(7);
+
+    GetHMC6352Parameters();
+
+    TxString("\r\nRegisters\r\n");
+    TxString("\t0:\tI2C");
+    TxString("\t 0x");
+    TxValH(CP[0]);
+    if ( CP[0] != (uint8)0x42 )
+        TxString("\t Error expected 0x42 for HMC6352");
+    TxNextLine();
+
+    Temp = (CP[1]*256)|CP[2];
+    TxString("\t1:2:\tXOffset\t");
+    TxVal32((int32)Temp, 0, 0);
+    TxNextLine();
+
+    Temp = (CP[3]*256)|CP[4];
+    TxString("\t3:4:\tYOffset\t");
+    TxVal32((int32)Temp, 0, 0);
+    TxNextLine();
+
+    TxString("\t5:\tDelay\t");
+    TxVal32((int32)CP[5], 0, 0);
+    TxNextLine();
+
+    TxString("\t6:\tNSum\t");
+    TxVal32((int32)CP[6], 0, 0);
+    TxNextLine();
+
+    TxString("\t7:\tSW Ver\t");
+    TxString(" 0x");
+    TxValH(CP[7]);
+    TxNextLine();
+
+    TxString("\t8:\tOpMode:");
+    switch ( ( CP[8] >> 5 ) & 0x03 ) {
+        case 0:
+            TxString("  1Hz");
+            break;
+        case 1:
+            TxString("  5Hz");
+            break;
+        case 2:
+            TxString("  10Hz");
+            break;
+        case 3:
+            TxString("  20Hz");
+            break;
+    }
+
+    if ( CP[8] & 0x10 ) TxString(" S/R");
+
+    switch ( CP[8] & 0x03 ) {
+        case 0:
+            TxString(" Standby");
+            break;
+        case 1:
+            TxString(" Query");
+            break;
+        case 2:
+            TxString(" Continuous");
+            break;
+        case 3:
+            TxString(" Not-allowed");
+            break;
+    }
+    TxNextLine();
+
+    InitCompass();
+    if ( !F.CompassValid ) goto CTerror;
+
+    Delay1mS(50);
+
+    ReadHMC6352();
+    if ( F.CompassMissRead ) goto CTerror;
+
+    TxNextLine();
+    TxVal32(MagHeading * RADDEG * 10.0, 1, 0);
+    TxString(" deg (Magnetic)\r\n");   
+    Heading = Headingp = Make2Pi( MagHeading - MagDeviation - CompassOffset );
+    TxVal32(Heading * RADDEG * 10.0, 1, 0);
+    TxString(" deg (True)\r\n");
+
+    return;
+CTerror:
+    I2CCOMPASS.stop();
+    TxString("FAIL\r\n");
+} // DoHMC6352Test
+
+void CalibrateHMC6352(void) {   // calibrate the compass by rotating the ufo through 720 deg smoothly
+    TxString("\r\nCalib. compass - Press CONTINUE button (x) to Start\r\n");
+    while ( PollRxChar() != 'x' ); // UAVPSet uses 'x' for CONTINUE button
+
+    // Do Set/Reset now
+    if ( WriteByteHMC6352('O') != I2C_ACK ) goto CCerror;
+
+    Delay1mS(7);
+
+    // set Compass device to Calibration mode
+    if ( WriteByteHMC6352('C') != I2C_ACK ) goto CCerror;
+
+    TxString("\r\nRotate horizontally 720 deg in ~30 sec. - Press CONTINUE button (x) to Finish\r\n");
+    while ( PollRxChar() != 'x' );
+
+    // set Compass device to End-Calibration mode
+    if ( WriteByteHMC6352('E') != I2C_ACK ) goto CCerror;
+
+    TxString("\r\nCalibration complete\r\n");
+
+    Delay1mS(50);
+
+    InitCompass();
+
+    return;
+
+CCerror:
+    TxString("Calibration FAILED\r\n");
+} // CalibrateHMC6352
+
+void InitHMC6352(void) {
+
+    // 20Hz continuous read with periodic reset.
+#ifdef SUPPRESS_COMPASS_SR
+#define COMP_OPMODE 0x62
+#else
+#define COMP_OPMODE 0x72
+#endif // SUPPRESS_COMPASS_SR
+
+    // Set device to Compass mode
+    I2CCOMPASS.start();
+    if ( I2CCOMPASS.write(HMC6352_ID) != I2C_ACK ) goto CTerror;
+    if ( I2CCOMPASS.write('G')  != I2C_ACK ) goto CTerror;
+    if ( I2CCOMPASS.write(0x74) != I2C_ACK ) goto CTerror;
+    if ( I2CCOMPASS.write(COMP_OPMODE) != I2C_ACK ) goto CTerror;
+    I2CCOMPASS.stop();
+
+    Delay1mS(1);
+
+    // save operation mode in Flash
+    if ( WriteByteHMC6352('L') != I2C_ACK ) goto CTerror;
+
+    Delay1mS(1);
+
+    // Do Bridge Offset Set/Reset now
+    if ( WriteByteHMC6352('O') != I2C_ACK ) goto CTerror;
+
+    Delay1mS(50);
+
+    F.CompassValid = true;
+
+    return;
+CTerror:
+    F.CompassValid = false;
+    Stats[CompassFailS]++;
+    F.CompassFailure = true;
+
+    I2CCOMPASS.stop();
+} // InitHMC6352
+
+boolean HMC6352Active(void) {
+
+    I2CCOMPASS.start();
+    F.CompassValid = !(I2CCOMPASS.write(HMC6352_ID) != I2C_ACK);
+    I2CCOMPASS.stop();
+
+    if ( F.CompassValid )
+        TrackMinI2CRate(100000);
+
+    return ( F.CompassValid );
+
+} // HMC6352Active
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/control.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,437 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+void DoAltitudeHold(void);
+void UpdateAltitudeSource(void);
+void AltitudeHold(void);
+void InertialDamping(void);
+void DoOrientationTransform(void);
+void DoControl(void);
+
+void CheckThrottleMoved(void);
+void LightsAndSirens(void);
+void InitControl(void);
+
+real32 Angle[3], Anglep[3], Rate[3], Ratep[3]; // Milliradians
+real32 Comp[4];
+real32 DescentComp;
+
+real32 AngleE[3], AngleIntE[3];
+
+real32 GS;
+real32 Rl, Pl, Yl, Ylp;
+int16 HoldYaw;
+int16 CruiseThrottle, MaxCruiseThrottle, DesiredThrottle, IdleThrottle, InitialThrottle, StickThrottle;
+int16 DesiredRoll, DesiredPitch, DesiredYaw, DesiredHeading, DesiredCamPitchTrim;
+real32 ControlRoll, ControlPitch, ControlRollP, ControlPitchP;
+int16 CurrMaxRollPitch;
+
+int16 AttitudeHoldResetCount;
+real32 AltDiffSum, AltD, AltDSum;
+real32 DesiredAltitude, Altitude, AltitudeP;
+real32 ROC;
+
+uint32 AltuSp;
+int16 DescentLimiter;
+
+real32 GRollKp, GRollKi, GRollKd, GPitchKp, GPitchKi, GPitchKd;
+
+boolean    FirstPass;
+int8 BeepTick = 0;
+
+void DoAltitudeHold(void) { // Syncronised to baro intervals independant of active altitude source
+
+    static int16 NewAltComp;
+    static real32 AltP, AltI, AltD;
+    static real32 LimAltE, AltE;
+    static real32 AltdT, AltdTR;
+    static uint32 Now;
+
+    Now = uSClock();
+    AltdT = ( Now - AltuSp ) * 0.000001;
+    AltdT = Limit(AltdT, 0.01, 0.1); // limit range for restarts
+    AltdTR = 1.0 / AltdT;
+    AltuSp = Now;
+
+    AltE = DesiredAltitude - Altitude;
+    LimAltE = Limit(AltE, -ALT_BAND_M, ALT_BAND_M);
+
+    AltP = LimAltE * K[AltKp];
+    AltP = Limit(AltP, -ALT_MAX_THR_COMP, ALT_MAX_THR_COMP);
+
+    AltDiffSum += LimAltE;
+    AltDiffSum = Limit(AltDiffSum, -ALT_INT_WINDUP_LIMIT, ALT_INT_WINDUP_LIMIT);
+    AltI = AltDiffSum * K[AltKi] * AltdT;
+    AltI = Limit(AltDiffSum, -K[AltIntLimit], K[AltIntLimit]);
+
+    ROC = ( Altitude - AltitudeP ) * AltdTR; // may neeed filtering - noisy
+    AltitudeP = Altitude;
+
+    AltD = ROC * K[AltKd];
+    AltD = Limit(AltD, -ALT_MAX_THR_COMP, ALT_MAX_THR_COMP);
+
+    if ( ROC < ( -K[MaxDescentRateDmpS] * 10.0 ) ) {
+        DescentLimiter += 1;
+        DescentLimiter = Limit(DescentLimiter, 0, ALT_MAX_THR_COMP * 2.0);
+
+    } else
+        DescentLimiter = DecayX(DescentLimiter, 1);
+
+    NewAltComp = AltP + AltI + AltD + AltDSum + DescentLimiter;
+
+    NewAltComp = Limit(NewAltComp, -ALT_MAX_THR_COMP, ALT_MAX_THR_COMP);
+
+    Comp[Alt] = SlewLimit(Comp[Alt], NewAltComp, 1.0);
+
+
+    if ( ROC > Stats[MaxROCS] )
+        Stats[MaxROCS] = ROC;
+    else
+        if ( ROC < Stats[MinROCS] )
+            Stats[MinROCS] = ROC;
+
+} // DoAltitudeHold
+
+void UpdateAltitudeSource(void) {
+    if ( F.UsingRangefinderAlt )
+        Altitude = RangefinderAltitude;
+    else
+        Altitude = BaroRelAltitude;
+
+} // UpdateAltitudeSource
+
+void AltitudeHold() {
+    static int16 NewCruiseThrottle;
+
+    GetBaroAltitude();
+    GetRangefinderAltitude();
+    CheckThrottleMoved();
+
+    if ( F.AltHoldEnabled ) {
+        if ( F.NewBaroValue  ) { // sync on Baro which MUST be working
+            F.NewBaroValue = false;
+
+            UpdateAltitudeSource();
+
+            if ( ( NavState != HoldingStation ) && F.AllowNavAltitudeHold ) { // Navigating - using CruiseThrottle
+                F.HoldingAlt = true;
+                DoAltitudeHold();
+            } else
+                if ( F.ThrottleMoving ) {
+                    F.HoldingAlt = false;
+                    DesiredAltitude = Altitude;
+                    Comp[Alt] = Decay1(Comp[Alt]);
+                } else {
+                    F.HoldingAlt = true;
+                    if ( fabs(ROC) < ALT_HOLD_MAX_ROC_MPS  ) {
+                        NewCruiseThrottle = DesiredThrottle + Comp[Alt];
+                        CruiseThrottle = HardFilter(CruiseThrottle, NewCruiseThrottle);
+                        CruiseThrottle = Limit( CruiseThrottle , IdleThrottle, MaxCruiseThrottle );
+                    }
+                    DoAltitudeHold();
+                }
+        }
+    } else {
+        Comp[Alt] = Decay1(Comp[Alt]);
+        ROC = 0.0;
+        F.HoldingAlt = false;
+    }
+} // AltitudeHold
+
+void InertialDamping(void) { // Uses accelerometer to damp disturbances while holding altitude
+    static uint8 i;
+
+    if ( F.AccelerationsValid  && F.NearLevel ) {
+        // Up - Down
+
+        Vel[UD] += Acc[UD] * dT;
+        Comp[UD] = Vel[UD] * K[VertDampKp];
+        Comp[UD] = Limit(Comp[UD], DAMP_VERT_LIMIT_LOW, DAMP_VERT_LIMIT_HIGH);
+
+        Vel[UD] = DecayX(Vel[UD], K[VertDampDecay]);
+
+        // Lateral compensation only when holding altitude
+        if ( F.HoldingAlt && F.AttitudeHold ) {
+            if ( F.WayPointCentred ) {
+                // Left - Right
+                Vel[LR] += Acc[LR] * dT;
+                Comp[LR] = Vel[LR] * K[HorizDampKp];
+                Comp[LR] = Limit(Comp[LR], -DAMP_HORIZ_LIMIT, DAMP_HORIZ_LIMIT);
+                Vel[LR] = DecayX(Vel[LR], K[HorizDampDecay]);
+
+                // Back - Front
+                Vel[BF] += Acc[BF] * dT;
+                Comp[BF] = Vel[BF] * K[HorizDampKp];
+                Comp[BF] = Limit(Comp[BF], -DAMP_HORIZ_LIMIT, DAMP_HORIZ_LIMIT);
+                Vel[BF] = DecayX(Vel[BF], K[HorizDampDecay]);
+            } else {
+                Vel[LR] = Vel[BF] = 0;
+                Comp[LR] = Decay1(Comp[LR]);
+                Comp[BF] = Decay1(Comp[BF]);
+            }
+        } else {
+            Vel[LR] = Vel[BF] = 0;
+
+            Comp[LR] = Decay1(Comp[LR]);
+            Comp[BF] = Decay1(Comp[BF]);
+        }
+    } else
+        for ( i = 0; i < (uint8)3; i++ )
+            Comp[i] = Vel[i] = 0.0;
+
+} // InertialDamping
+
+void DoOrientationTransform(void) {
+    static real32 OSO, OCO;
+
+    if ( F.UsingPolar ) {
+        OSO = OSin[PolarOrientation];
+        OCO = OCos[PolarOrientation];
+    } else {
+        OSO = OSin[Orientation];
+        OCO = OCos[Orientation];
+    }
+
+    if ( !F.NavigationActive )
+        NavCorr[Roll] = NavCorr[Pitch] = NavCorr[Yaw] = 0;
+
+    // -PS+RC
+    ControlRoll = (int16)( -DesiredPitch * OSO + DesiredRoll * OCO );
+
+    // PC+RS
+    ControlPitch = (int16)( DesiredPitch * OCO + DesiredRoll * OSO );
+
+} // DoOrientationTransform
+
+void GainSchedule(boolean UseAngle) {
+
+    /*
+    // rudimentary gain scheduling (linear)
+    static int16 AttDiff, ThrDiff;
+
+    if ( (!F.NavigationActive) || ( F.NavigationActive && (NavState == HoldingStation ) ) )
+    {
+        // also density altitude?
+
+        if ( P[Acro] > 0) // due to Foliage 2009 and Alexinparis 2010
+        {
+             AttDiff = CurrMaxRollPitch  - ATTITUDE_HOLD_LIMIT;
+            GS = GS * ( 1000.0 - (AttDiff * (int16)P[Acro]) );
+            GS *= 0.001;
+            GS = Limit(GS, 0, 1.0);
+        }
+
+        if ( P[GSThrottle] > 0 )
+        {
+             ThrDiff = DesiredThrottle - CruiseThrottle;
+            GS = (int32)GS * ( 1000.0 + (ThrDiff * (int16)P[GSThrottle]) );
+            GS *= 0.001;
+        }
+    }
+
+    */
+
+    GS = 1.0; // Temp
+
+    GRollKp = K[RollKp];
+    GRollKi = K[RollKi];
+    GRollKd = K[RollKd];
+
+    GPitchKp = K[PitchKp];
+    GPitchKi = K[PitchKi];
+    GPitchKd = K[PitchKd];
+
+} // GainSchedule
+
+void DoControl(void) {
+    GetAttitude();
+    AltitudeHold();
+    InertialDamping();
+
+#ifdef SIMULATE
+
+    FakeDesiredRoll = DesiredRoll + NavRCorr;
+    FakeDesiredPitch = DesiredPitch + NavPCorr;
+    FakeDesiredYaw =  DesiredYaw + NavYCorr;
+    Angle[Roll] = SlewLimit(Angle[Roll], FakeDesiredRoll * 16.0, 4.0);
+    Angle[Pitch] = SlewLimit(Angle[Pitch], FakeDesiredPitch * 16.0, 4.0);
+    Angle[Yaw] = SlewLimit(Angle[Yaw], FakeDesiredYaw, 4.0);
+    Rl = FakeDesiredRoll;
+    Pl = FakeDesiredPitch;
+    Yl = DesiredYaw;
+
+#else
+
+    DoOrientationTransform();
+
+    GainSchedule(F.UsingAngleControl);
+
+#ifdef DISABLE_EXTRAS
+    // for commissioning
+    Comp[BF] = Comp[LR] = Comp[UD] = Comp[Alt] = 0;
+    NavCorr[Roll] = NavCorr[Pitch] = NavCorr[Yaw] = 0;
+
+    F.UsingAngleControl = false;
+
+#endif // DISABLE_EXTRAS
+
+    if ( F.UsingAngleControl ) {
+        // Roll
+
+        AngleE[Roll] = ( ControlRoll * ATTITUDE_SCALE ) - Angle[Roll];
+        AngleIntE[Roll] += AngleE[Roll] * dT;
+        AngleIntE[Roll] = Limit(AngleIntE[Roll], -K[RollIntLimit], K[RollIntLimit]);
+        Rl  = -(AngleE[Roll] * GRollKp + AngleIntE[Roll] * GRollKi + Rate[Roll] * GRollKd * dTR);
+        Rl -=  NavCorr[Roll] - Comp[LR];
+
+        // Pitch
+
+        AngleE[Pitch] = ( ControlPitch * ATTITUDE_SCALE ) - Angle[Pitch];
+        AngleIntE[Pitch] += AngleE[Pitch] * dT;
+        AngleIntE[Pitch] = Limit(AngleIntE[Pitch], -K[PitchIntLimit], K[PitchIntLimit]);
+        Pl  = -(AngleE[Pitch] * GPitchKp + AngleIntE[Pitch] * GPitchKi + Rate[Pitch] * GPitchKd * dTR);
+        Pl -= NavCorr[Pitch] - Comp[BF];
+
+    } else {
+        // Roll
+
+        AngleE[Roll] = Limit(Angle[Roll],  -K[RollIntLimit], K[RollIntLimit]);
+        Rl  = Rate[Roll] * GRollKp + AngleE[Roll] * GRollKi + (Rate[Roll]-Ratep[Roll]) * GRollKd * dTR;
+        Rl -=  NavCorr[Roll] - Comp[LR];
+
+        Rl *= GS;
+
+        Rl -= ControlRoll;
+
+        ControlRollP = ControlRoll;
+        Ratep[Roll] = Rate[Roll];
+
+        // Pitch
+
+        AngleE[Pitch] = Limit(Angle[Pitch],  -K[PitchIntLimit], K[PitchIntLimit]);
+        Pl  = Rate[Pitch] * GPitchKp + AngleE[Pitch] * GPitchKi + (Rate[Pitch]-Ratep[Pitch]) * GPitchKd * dTR;
+        Pl -= NavCorr[Pitch] - Comp[BF];
+
+        Pl *= GS;
+
+        Pl -= ControlPitch;
+
+        ControlPitchP = ControlPitch;
+        Ratep[Pitch] = Rate[Pitch];
+    }
+
+    // Yaw
+
+    Rate[Yaw] -= NavCorr[Yaw];
+    if ( abs(DesiredYaw) > 5 )
+        Rate[Yaw] -= DesiredYaw;
+
+    Yl  = Rate[Yaw] * K[YawKp] + Angle[Yaw] * K[YawKi] + (Rate[Yaw]-Ratep[Yaw]) * K[YawKd] * dTR;
+    Ratep[Yaw] = Rate[Yaw];
+
+#ifdef TRICOPTER
+    Yl = SlewLimit(Ylp, Yl, 2.0);
+    Ylp = Yl;
+    Yl = Limit(Yl, -K[YawLimit] * 4.0, K[YawLimit] * 4.0);
+#else
+    Yl = Limit(Yl, -K[YawLimit], K[YawLimit]);
+#endif // TRICOPTER
+
+#endif // SIMULATE        
+
+} // DoControl
+
+static int8 RCStart = RC_INIT_FRAMES;
+
+void LightsAndSirens(void) {
+    static int24 Ch5Timeout;
+
+    LEDYellow_TOG;
+    if ( F.Signal ) LEDGreen_ON;
+    else LEDGreen_OFF;
+
+    Beeper_OFF;
+    Ch5Timeout = mSClock() + 500;                     // mS.
+
+    do {
+
+        ProcessCommand();
+
+        if ( F.Signal ) {
+            LEDGreen_ON;
+            if ( F.RCNewValues ) {
+                UpdateControls();
+                if ( --RCStart == 0 ) { // wait until RC filters etc. have settled
+                    UpdateParamSetChoice();
+                    MixAndLimitCam();
+                    RCStart = 1;
+                }
+
+                InitialThrottle = StickThrottle;
+                StickThrottle = 0;
+                OutSignals();
+                if ( mSClock() > Ch5Timeout ) {
+                    if ( F.Navigate || F.ReturnHome || !F.ParametersValid ) {
+                        Beeper_TOG;
+                        LEDRed_TOG;
+                    } else
+                        if ( Armed )
+                            LEDRed_TOG;
+
+                    Ch5Timeout += 500;
+                }
+            }
+        } else {
+            LEDRed_ON;
+            LEDGreen_OFF;
+        }
+        ReadParameters();
+        GetIRAttitude(); // only active if IRSensors selected
+    } while ((!F.Signal) || (Armed && FirstPass) || F.Ch5Active || F.GyroFailure || (!F.AccelerationsValid) ||
+             ( InitialThrottle >= RC_THRES_START ) || (!F.ParametersValid) );
+
+    FirstPass = false;
+
+    Beeper_OFF;
+    LEDRed_OFF;
+    LEDGreen_ON;
+    LEDYellow_ON;
+
+    mS[LastBattery] = mSClock();
+    mS[FailsafeTimeout] = mSClock() + FAILSAFE_TIMEOUT_MS;
+
+    F.LostModel = false;
+    FailState = MonitoringRx;
+
+} // LightsAndSirens
+
+void InitControl(void) {
+    static uint8 i;
+
+    AltuSp = DescentLimiter = 0;
+
+    for ( i = 0; i < (uint8)3; i++ )
+        AngleE[i] = AngleIntE[i] = Angle[i] = Anglep[i] = Rate[i] = Trim[i] = Vel[i] = Comp[i] = 0.0;
+
+    Comp[Alt] = AltSum = Ylp = ControlRollP = ControlPitchP = AltitudeP = 0.0;
+
+} // InitControl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gps.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,562 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+void UpdateField(void);
+int32 ConvertGPSToM(int32);
+int32 ConvertMToGPS(int32);
+int24 ConvertInt(uint8, uint8);
+real32 ConvertReal(uint8, uint8);
+int32 ConvertLatLonM(uint8, uint8);
+void ConvertUTime(uint8, uint8);
+void ConvertUDate(uint8, uint8);
+void ParseGPGGASentence(void);
+void ParseGPRMCSentence(void);
+void SetGPSOrigin(void);
+void ParseGPSSentence(void);
+void RxGPSPacket(uint8);
+void SetGPSOrigin(void);
+void DoGPS(void);
+void GPSTest(void);
+void UpdateGPS(void);
+void InitGPS(void);
+
+const uint8 NMEATags[MAX_NMEA_SENTENCES][5]= {
+    // NMEA
+    {'G','P','G','G','A'}, // full positioning fix
+    {'G','P','R','M','C'}, // main current position and heading
+};
+
+NMEAStruct NMEA;
+
+uint8     GPSPacketTag;
+struct    tm  GPSTime;
+int32     GPSStartTime, GPSSeconds;
+int32     GPSLatitude, GPSLongitude;
+int32     OriginLatitude, OriginLongitude;
+int32     DesiredLatitude, DesiredLongitude;
+int32     LatitudeP, LongitudeP, HoldLatitude, HoldLongitude;
+real32    GPSAltitude, GPSRelAltitude, GPSOriginAltitude;
+real32    GPSLongitudeCorrection;
+real32    GPSHeading, GPSMagHeading, GPSMagDeviation, GPSVel, GPSVelp, GPSROC;
+int8      GPSNoOfSats;
+int8      GPSFix;
+int16     GPSHDilute;
+
+int32     FakeGPSLongitude, FakeGPSLatitude;
+
+uint8     ll, tt, ss, RxCh;
+uint8     GPSCheckSumChar, GPSTxCheckSum;
+uint8     nll, cc, lo, hi;
+boolean   EmptyField;
+int16     ValidGPSSentences;
+real32    GPSdT, GPSdTR;
+uint32    GPSuSp;
+
+int32     SumGPSRelAltitude, SumBaroRelAltitude;
+
+int32 ConvertGPSToM(int32 c) {   // approximately 1.8553257183 cm per LSB at the Equator
+    // conversion max is 21Km
+    return ( ((int32)c * (int32)1855)/((int32)100000) );
+} // ConvertGPSToM
+
+int32 ConvertMToGPS(int32 c) {
+    // conversion max is 21Km
+    return ( ((int32)c * (int32)100000)/((int32)1855) );
+} // ConvertMToGPS
+
+int24 ConvertInt(uint8 lo, uint8 hi) {
+    static uint8 i;
+    static int24 r;
+
+    r = 0;
+    if ( !EmptyField )
+        for (i = lo; i <= hi ; i++ )
+            r = r * 10 + NMEA.s[i] - '0';
+
+    return (r);
+} // ConvertInt
+
+real32 ConvertReal(uint8 lo, uint8 hi) {
+    int16 i, n, dp;
+    boolean Positive;
+    int16 whole;
+    real32 rval;
+
+    if (EmptyField)
+        rval=0.0;
+    else {
+        if (NMEA.s[lo]=='-') {
+            Positive=false;
+            lo++;
+        } else
+            Positive=true;
+
+        dp=lo;
+        while ((NMEA.s[dp] != '.')&&(dp<=hi))
+            dp++;
+
+        whole=ConvertInt(lo, dp-1);
+        rval=ConvertInt(dp + 1, hi);
+
+        n=hi-dp;
+        for (i=1;i<=n;i++)
+            rval/=10.0;
+
+        if (Positive)
+            rval=(whole+rval);
+        else
+            rval=-(whole+rval);
+    }
+
+    return(rval);
+} // ConvertReal
+
+int32 ConvertLatLonM(uint8 lo, uint8 hi) {    // NMEA coordinates normally assumed as DDDMM.MMMMM ie 5 decimal minute digits
+    // but code can deal with 4 and 5 decimal minutes
+    // Positions are stored at 5 decimal minute NMEA resolution which is
+    // approximately 1.855 cm per LSB at the Equator.
+    static int32 dd, mm, dm, r;
+    static uint8 dp;
+
+    r = 0;
+    if ( !EmptyField ) {
+        dp = lo + 4; // could do this in initialisation for Lat and Lon?
+        while ( NMEA.s[dp] != '.') dp++;
+
+        dd = ConvertInt(lo, dp - 3);
+        mm = ConvertInt(dp - 2 , dp - 1);
+        if ( ( hi - dp ) > (uint8)4 )
+            dm = ConvertInt(dp + 1, dp + 5);
+        else
+            dm = ConvertInt(dp + 1, dp + 4) * 10L;
+
+        r = dd * 6000000 + mm * 100000 + dm;
+    }
+
+    return(r);
+} // ConvertLatLonM
+
+void ConvertUTime(uint8 lo, uint8 hi) {
+
+    if ( !EmptyField ) {
+        GPSTime.tm_hour = ConvertInt(lo, lo+1);
+        GPSTime.tm_min = ConvertInt(lo+2, lo+3);
+        GPSTime.tm_sec = ConvertInt(lo+4, lo+5);
+        GPSSeconds = (int32)GPSTime.tm_hour * 3600 + GPSTime.tm_min * 60 + GPSTime.tm_sec;
+    }
+} // ConvertUTime
+
+void ConvertUDate(uint8 lo, uint8 hi) {
+
+    static time_t seconds;
+
+//   if ( !EmptyField && !F.RTCValid )
+    {
+        GPSTime.tm_mday = ConvertInt(lo, lo + 1);
+        GPSTime.tm_mon = ConvertInt(lo + 2, lo + 3) - 1;
+        GPSTime.tm_year = ConvertInt( lo + 4, hi ) + 100;
+        seconds = mktime ( &GPSTime );
+        set_time( seconds );
+
+        F.RTCValid = true;
+    }
+
+} // ConvertUDate
+
+void UpdateField(void) {
+    static uint8 ch;
+
+    lo = cc;
+
+    ch = NMEA.s[cc];
+    while (( ch != ',' ) && ( ch != '*' ) && ( cc < nll ))
+        ch = NMEA.s[++cc];
+
+    hi = cc - 1;
+    cc++;
+    EmptyField = hi < lo;
+} // UpdateField
+
+void ParseGPGGASentence(void) {    // full position $GPGGA fix
+
+    UpdateField();
+
+    UpdateField();   //UTime
+    ConvertUTime(lo,hi);
+
+    UpdateField();       //Lat
+    GPSLatitude = ConvertLatLonM(lo, hi);
+    UpdateField();   //LatH
+    if (NMEA.s[lo] == 'S') GPSLatitude = -GPSLatitude;
+
+    UpdateField();       //Lon
+    GPSLongitude = ConvertLatLonM(lo, hi);
+    UpdateField();       //LonH
+    if (NMEA.s[lo] == 'W') GPSLongitude = -GPSLongitude;
+
+    UpdateField();       //Fix
+    GPSFix = (uint8)(ConvertInt(lo,hi));
+
+    UpdateField();       //Sats
+    GPSNoOfSats = (uint8)(ConvertInt(lo,hi));
+
+    UpdateField();       // HDilute
+    GPSHDilute = ConvertInt(lo, hi-3) * 100 + ConvertInt(hi-1, hi); // Cm
+
+    UpdateField();       // Alt
+    GPSAltitude = real32(ConvertInt(lo, hi-2) * 10L + ConvertInt(hi, hi)); // Metres
+
+    //UpdateField();   // AltUnit - assume Metres!
+
+    //UpdateField();   // GHeight
+    //UpdateField();   // GHeightUnit
+
+    F.GPSValid = (GPSFix >= GPS_MIN_FIX) && ( GPSNoOfSats >= GPS_MIN_SATELLITES );
+
+    if ( State == InFlight ) {
+        if ( GPSHDilute > Stats[MaxHDiluteS] ) {
+            Stats[MaxHDiluteS] = GPSHDilute;
+            F.GPSFailure = GPSHDilute > 150;
+        } else
+            if ( GPSHDilute < Stats[MinHDiluteS] )
+                Stats[MinHDiluteS] = GPSHDilute;
+
+        if ( GPSNoOfSats > Stats[GPSMaxSatsS] )
+            Stats[GPSMaxSatsS] = GPSNoOfSats;
+        else
+            if ( GPSNoOfSats < Stats[GPSMinSatsS] )
+                Stats[GPSMinSatsS] = GPSNoOfSats;
+    }
+} // ParseGPGGASentence
+
+void ParseGPRMCSentence() { // main current position and heading
+
+    // uint32 UTime;
+
+    UpdateField();
+
+    UpdateField();   //UTime
+    //UTime = ConvertUTime(lo,hi);
+    // GPSMissionTime =(int) (UTime-GPSStartTime);
+
+    UpdateField();
+    if ( NMEA.s[lo] == 'A' ) {
+        UpdateField();   //Lat
+        GPSLatitude = ConvertLatLonM(lo,hi);
+        UpdateField();   //LatH
+        if (NMEA.s[lo] == 'S')
+            GPSLatitude= -GPSLatitude;
+
+        UpdateField();   //Lon
+        GPSLongitude = ConvertLatLonM(lo,hi);
+
+        UpdateField();   //LonH
+        if ( NMEA.s[lo] == 'W' )
+           GPSLongitude = -GPSLongitude;
+
+        UpdateField();   // Groundspeed (Knots)
+        GPSVel = ConvertReal(lo, hi) * 0.514444444; // KTTOMPS
+
+        UpdateField();   // True course made good (Degrees)
+        GPSHeading = ConvertReal(lo, hi) * DEGRAD;
+
+        UpdateField();   //UDate
+        ConvertUDate(lo, hi);
+
+        UpdateField();   // Magnetic Deviation (Degrees)
+        GPSMagDeviation = ConvertReal(lo, hi) * DEGRAD;
+
+        UpdateField();   // East/West
+        if ( NMEA.s[lo] == 'W')
+            GPSMagHeading = GPSHeading - GPSMagDeviation; // need to check sign????
+        else
+            GPSMagHeading = GPSHeading +  GPSMagDeviation;
+        F.HaveGPRMC = true;
+    } else
+        F.HaveGPRMC = false;
+
+} // ParseGPRMCSentence
+
+void SetGPSOrigin(void) {
+    if ( ( ValidGPSSentences == GPS_ORIGIN_SENTENCES ) && F.GPSValid ) {
+        GPSStartTime = GPSSeconds;
+        OriginLatitude = DesiredLatitude = HoldLatitude = LatitudeP = GPSLatitude;
+        OriginLongitude = DesiredLongitude = HoldLongitude = LongitudeP = GPSLongitude;
+        GPSVel = 0;
+
+#ifdef SIMULATE
+        FakeGPSLongitude = GPSLongitude;
+        FakeGPSLatitude = GPSLatitude;
+#endif // SIMULATE
+
+        mS[LastGPS] = mSClock();
+
+        GPSLongitudeCorrection = cos(fabs((real32)(GPSLatitude/600000L) * DEGRAD));
+
+        GPSOriginAltitude = GPSAltitude;
+
+        Write16PX(NAV_ORIGIN_ALT, (int16)(GPSAltitude/100));
+        Write32PX(NAV_ORIGIN_LAT, GPSLatitude);
+        Write32PX(NAV_ORIGIN_LON, GPSLongitude);
+
+        if ( !F.NavValid ) {
+            DoBeep100mS(2,0);
+            Stats[NavValidS] = true;
+            F.NavValid = true;
+        }
+        F.AcquireNewPosition = true;
+    }
+} // SetGPSOrigin
+
+void ParseGPSSentence(void) {
+    static uint32 Now;
+
+#define FAKE_NORTH_WIND       0L
+#define FAKE_EAST_WIND        0L
+#define SCALE_VEL             64L
+
+    cc = 0;
+    nll = NMEA.length;
+
+    switch ( GPSPacketTag ) {
+        case GPGGAPacketTag:
+            ParseGPGGASentence();
+            break;
+        case GPRMCPacketTag:
+            ParseGPRMCSentence();
+            break;
+    }
+
+    if ( F.GPSValid ) {
+        // all coordinates in 0.00001 Minutes or ~1.8553cm relative to Origin
+        // There is a lot of jitter in position - could use Kalman Estimator?
+
+        Now = uSClock();
+        GPSdT = ( Now - GPSuSp) * 0.0000001;
+        GPSdTR = 1.0 / GPSdT;
+        GPSuSp = Now;
+
+        if ( ValidGPSSentences <  GPS_ORIGIN_SENTENCES ) {  // repetition to ensure GPGGA altitude is captured
+            F.GPSValid = false;
+
+            if ( ( GPSPacketTag == GPGGAPacketTag ) && ( GPSHDilute <= GPS_MIN_HDILUTE ))
+                ValidGPSSentences++;
+            else
+                ValidGPSSentences = 0;
+        }
+
+#ifdef SIMULATE
+
+        if ( State == InFlight ) { // don't bother with GPS longitude correction for now?
+            CosH = int16cos(Heading);
+            SinH = int16sin(Heading);
+            GPSLongitude = FakeGPSLongitude + ((int32)(-FakeDesiredPitch) * SinH)/SCALE_VEL;
+            GPSLatitude = FakeGPSLatitude + ((int32)(-FakeDesiredPitch) * CosH)/SCALE_VEL;
+
+            A = Make2Pi(Heading + HALFMILLIPI);
+            CosH = int16cos(A);
+            SinH = int16sin(A);
+            GPSLongitude += ((int32)FakeDesiredRoll * SinH) / SCALE_VEL;
+            GPSLongitude += FAKE_EAST_WIND; // wind
+            GPSLatitude += ((int32)FakeDesiredRoll * CosH) / SCALE_VEL;
+            GPSLatitude += FAKE_NORTH_WIND; // wind
+
+            FakeGPSLongitude = GPSLongitude;
+            FakeGPSLatitude = GPSLatitude;
+
+            GPSRelAltitude = BaroRelAltitude;
+        }
+
+#else
+        if (F.NavValid )
+            GPSRelAltitude = GPSAltitude - GPSOriginAltitude;
+
+#endif // SIMULATE
+
+        // possibly add GPS filtering here
+
+        if ( State == InFlight ) {
+            if ( GPSRelAltitude > Stats[GPSAltitudeS] )
+                Stats[GPSAltitudeS] = GPSRelAltitude;
+
+            if ( GPSVel * 10.0 > Stats[GPSVelS] )
+                Stats[GPSVelS] = GPSVel * 10.0;
+
+            if (( BaroRelAltitude > 5.0 ) && ( BaroRelAltitude < 15.0 )) { // 5-15M
+                SumGPSRelAltitude += GPSRelAltitude;
+                SumBaroRelAltitude += BaroRelAltitude;
+            }
+        }
+    } else
+        if ( State == InFlight )
+            Stats[GPSInvalidS]++;
+
+} // ParseGPSSentence
+
+void RxGPSPacket(uint8 RxCh) {
+
+    switch ( RxState ) {
+        case WaitCheckSum:
+            if (GPSCheckSumChar < (uint8)2) {
+                GPSTxCheckSum *= 16;
+                if ( RxCh >= 'A' )
+                    GPSTxCheckSum += ( RxCh - ('A' - 10) );
+                else
+                    GPSTxCheckSum += ( RxCh - '0' );
+
+                GPSCheckSumChar++;
+            } else {
+                NMEA.length = ll;
+                F.GPSPacketReceived = GPSTxCheckSum == RxCheckSum;
+                RxState = WaitSentinel;
+            }
+            break;
+        case WaitBody:
+            if ( RxCh == '*' ) {
+                GPSCheckSumChar = GPSTxCheckSum = 0;
+                RxState = WaitCheckSum;
+            } else
+                if ( RxCh == '$' ) { // abort partial Sentence
+                    ll = tt = RxCheckSum = 0;
+                    RxState = WaitTag;
+                } else {
+                    RxCheckSum ^= RxCh;
+                    NMEA.s[ll++] = RxCh;
+                    if ( ll > (uint8)( GPSRXBUFFLENGTH-1 ) )
+                        RxState = WaitSentinel;
+                }
+
+            break;
+        case WaitTag:
+            RxCheckSum ^= RxCh;
+            while ( ( RxCh != NMEATags[ss][tt] ) && ( ss < MAX_NMEA_SENTENCES ) ) ss++;
+            if ( RxCh == NMEATags[ss][tt] )
+                if ( tt == (uint8)NMEA_TAG_INDEX ) {
+                    GPSPacketTag = ss;
+                    RxState = WaitBody;
+                } else
+                    tt++;
+            else
+                RxState = WaitSentinel;
+            break;
+        case WaitSentinel: // highest priority skipping unused sentence types
+            if ( RxCh == '$' ) {
+                ll = tt = ss = RxCheckSum = 0;
+                RxState = WaitTag;
+            }
+            break;
+    }
+} // RxGPSPacket
+
+void UpdateGPS(void) {
+    if ( F.GPSPacketReceived ) {
+        LEDBlue_TOG;
+        F.GPSPacketReceived = false;
+        ParseGPSSentence();
+        if ( F.GPSValid ) {
+            F.NavComputed = false;
+            mS[GPSTimeout] = mSClock() + GPS_TIMEOUT_MS;
+        } else {
+            NavCorr[Pitch] = DecayX(NavCorr[Pitch], 2);
+            NavCorr[Roll] = DecayX(NavCorr[Roll], 2);
+            NavCorr[Yaw] = 0;
+        }
+    } else
+        if ( mSClock() > mS[GPSTimeout] )
+            F.GPSValid = false;
+
+    if ( F.GPSValid )
+        LEDRed_OFF;
+    else
+        LEDRed_ON;
+
+} // UpdateGPS
+
+void GPSTest(void) {
+
+    static uint8 i;
+
+    TxString("\r\nGPS test\r\n\r\n");
+
+    UpdateGPS();
+
+    UpdateRTC();
+    i = 0;
+    while ( RTCString[i] != NULL )
+        TxChar(RTCString[i++]);
+    TxNextLine();
+    TxString("Fix:     \t");
+    TxVal32(GPSFix,0,0);
+    TxNextLine();
+    TxString("Sats:    \t");
+    TxVal32(GPSNoOfSats,0,0);
+    TxNextLine();
+    TxString("HDilute: \t");
+    TxVal32(GPSHDilute,2,0);
+    TxNextLine();
+    TxString("Alt:     \t");
+    TxVal32(GPSAltitude,1,0);
+    TxNextLine();
+    TxString("Lat:     \t");
+    TxVal32(GPSLatitude/600, 4, 0);
+    TxNextLine();
+    TxString("Lon:     \t");
+    TxVal32(GPSLongitude/600, 4, 0);
+    if ( F.HaveGPRMC ) {
+        TxString("\r\nVel.   :\t");
+        TxVal32(GPSVel * 10.0 , 1, 0);
+        TxString("\r\nHeading:\t");
+        TxVal32(GPSHeading * RADDEG * 10.0 , 1, 0);
+        TxString("\r\nMDev.  :\t");
+        TxVal32(GPSMagDeviation * RADDEG * 10.0 , 1, 0);
+        TxNextLine();
+    }
+    TxNextLine();
+} // GPSTest
+
+void InitGPS(void) {
+    cc = 0;
+
+    GPSuSp = uSClock();
+
+    GPSLongitudeCorrection = 1.0;
+    GPSSeconds = GPSFix = GPSNoOfSats = GPSHDilute = 0;
+    GPSRelAltitude =  GPSAltitude = GPSMagDeviation = GPSHeading = GPSVel = 0.0;
+    GPSPacketTag = GPSUnknownPacketTag;
+
+    GPSTime.tm_hour = GPSTime.tm_min = GPSTime.tm_sec = GPSTime.tm_mday = GPSTime.tm_mon = GPSTime.tm_year = 0;
+
+    OriginLatitude = DesiredLatitude = HoldLatitude = LatitudeP = GPSLatitude = 0;
+    OriginLongitude = DesiredLongitude = HoldLongitude = LongitudeP = GPSLongitude = 0;
+
+    Write32PX(NAV_ORIGIN_LAT, 0);
+    Write32PX(NAV_ORIGIN_LON, 0);
+    Write16PX(NAV_ORIGIN_ALT, 0);
+
+    ValidGPSSentences = 0;
+
+    SumGPSRelAltitude = SumBaroRelAltitude = 0;
+
+    F.NavValid = F.GPSValid = F.GPSPacketReceived = false;
+    RxState = WaitSentinel;
+
+} // InitGPS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gyro.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,364 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+const real32 GyroToRadian[UnknownGyro] = {
+    0.023841,       // MLX90609
+    0.044680,       // ADXRS150
+    0.007149,       // IDG300
+    0.011796,       // LY530
+    0.017872,       // ADXRS300
+    0.000607,       // ITG3200
+    1.0             // Infrared Sensors
+    // add others as required
+};
+
+void ReadGyros(void);
+void GetGyroRates(void);
+void CheckGyroFault(uint8, uint8, uint8);
+void ErectGyros(void);
+void InitGyros(void);
+void GyroTest(void);
+void ShowGyroType(void);
+
+real32 GyroADC[3], GyroNeutral[3], Gyro[3]; // Radians
+uint8 GyroType;
+
+void GetGyroRates(void) {
+    static uint8 g;
+
+    ReadGyros();
+    for ( g = 0; g < (uint8)3; g++ )
+        Gyro[g] = ( GyroADC[g] - GyroNeutral[g] ) ;
+} // GetGyroRates
+
+void ReadGyros(void) {
+    switch ( GyroType ) {
+        case ITG3200Gyro:
+            ReadITG3200Gyro();
+            break;
+        case IRSensors:
+            GetIRAttitude();
+            break;
+        default :
+            ReadAnalogGyros();
+            break;
+    } // switch
+} // ReadGyros
+
+void ErectGyros(void) {
+    static int16 i, g;
+
+    LEDRed_ON;
+
+    for ( g = 0; g <(int8)3; g++ )
+        GyroNeutral[g] = 0.0;
+
+    for ( i = 0; i < 32 ; i++ ) {
+        Delay1mS(10);
+
+        ReadGyros();
+        for ( g = 0; g <(int8)3; g++ )
+            GyroNeutral[g] += GyroADC[g];
+    }
+
+    for ( g = 0; g <(int8)3; g++ ) {
+        GyroNeutral[g] *= 0.03125;
+        Gyro[g] = 0.0;
+    }
+
+    LEDRed_OFF;
+
+} // ErectGyros
+
+void GyroTest(void) {
+    TxString("\r\nGyro Test - ");
+    ShowGyroType();
+
+    ReadGyros();
+
+    TxString("\r\n\tRoll:   \t");
+    TxVal32(GyroADC[Roll] * 1000.0, 3, 0);
+    TxNextLine();
+    TxString("\tPitch:  \t");
+    TxVal32(GyroADC[Pitch] * 1000.0, 3, 0);
+    TxNextLine();
+    TxString("\tYaw:    \t");
+    TxVal32(GyroADC[Yaw] * 1000.0, 3, 0);
+    TxNextLine();
+
+    TxString("Expect ~0.0 ( ~0.5 for for analog gyros)\r\n");
+
+    switch ( GyroType ) {
+        case ITG3200Gyro:
+            ITG3200Test();
+            break;
+        default:
+            break;
+    } // switch
+
+    if ( F.GyroFailure )
+        TxString("\r\nFAILED\r\n");
+
+} // GyroTest
+
+void InitGyros(void) {
+    if ( ITG3200GyroActive() )
+        GyroType = ITG3200Gyro;
+    else
+        GyroType = P[GyroRollPitchType];
+
+    switch ( GyroType ) {
+        case ITG3200Gyro:
+            InitITG3200Gyro();
+            break;
+        case IRSensors:
+            InitIRSensors();
+        default:
+            InitAnalogGyros();
+            break;
+    } // switch
+
+    Delay1mS(50);
+    ErectGyros();
+
+} // InitGyros
+
+void ShowGyroType(void) {
+    switch ( GyroType ) {
+        case MLX90609Gyro:
+            TxString("MLX90609");
+            break;
+        case ADXRS150Gyro:
+            TxString("ADXRS613/150");
+            break;
+        case IDG300Gyro:
+            TxString("IDG300");
+            break;
+        case LY530Gyro:
+            TxString("ST-AY530");
+            break;
+        case ADXRS300Gyro:
+            TxString("ADXRS610/300");
+            break;
+        case ITG3200Gyro:
+            TxString("ITG3200");
+            break;
+        case IRSensors:
+            TxString("IR Sensors");
+            break;
+        default:
+            TxString("unknown");
+            break;
+    } // switch
+} // ShowGyroType
+
+//________________________________________________________________________________________
+
+// Analog Gyros
+
+void ReadAnalogGyros(void);
+void InitAnalogGyros(void);
+void CheckAnalogGyroFault(uint8, uint8, uint8);
+void AnalogGyroTest(void);
+
+void ReadAnalogGyros(void) {
+    static uint8 g;
+
+    GyroADC[Roll] = RollADC.read();
+    GyroADC[Pitch] = PitchADC.read();
+    GyroADC[Yaw] = YawADC.read();
+
+    for ( g = 0; g < (uint8)3; g++ )
+        GyroADC[g] *= GyroToRadian[GyroType];
+} // ReadAnalogGyros
+
+void InitAnalogGyros(void) {
+    // nothing to do
+    F.GyroFailure = false;
+} // InitAnalogGyros
+
+//________________________________________________________________________________________
+
+// ITG3200 3-axis I2C Gyro
+
+void ReadITG3200(void);
+uint8 ReadByteITG3200(uint8);
+void WriteByteITG3200(uint8, uint8);
+void InitITG3200(void);
+void ITG3200Test(void);
+boolean ITG3200Active(void);
+
+real32 ITG3200Temperature;
+
+void ReadITG3200Gyro(void) {
+    static char G[6];
+    static uint8 g;
+    static i16u GX, GY, GZ;
+
+    I2CGYRO.start();
+    if ( I2CGYRO.write(ITG3200_W) != I2C_ACK ) goto SGerror;
+    if ( I2CGYRO.write(ITG3200_GX_H) != I2C_ACK ) goto SGerror;
+    I2CGYRO.stop();
+
+    I2CGYRO.read(ITG3200_R, G, 6);
+
+    GX.b0 = G[1];
+    GX.b1 = G[0];
+    GY.b0 = G[3];
+    GY.b1 = G[2];
+    GZ.b0 = G[5];
+    GZ.b1 = G[4];
+
+    if ( F.Using9DOF ) { // SparkFun/QuadroUFO breakout pins forward components up 
+        GyroADC[Roll] = -(real32)GY.i16;
+        GyroADC[Pitch] = -(real32)GX.i16;
+        GyroADC[Yaw] = -(real32)GZ.i16;
+    } else { // SparkFun 6DOF breakout pins forward components down
+        GyroADC[Roll] = -(real32)GX.i16;
+        GyroADC[Pitch] = -(real32)GY.i16;
+        GyroADC[Yaw] = (real32)GZ.i16;
+    }
+
+    for ( g = 0; g < (uint8)3; g++ )
+        GyroADC[g] *= GyroToRadian[ITG3200Gyro];
+
+    return;
+
+SGerror:
+    I2CGYRO.stop();
+    // GYRO FAILURE - FATAL
+    Stats[GyroFailS]++;
+    F.GyroFailure = true;
+    return;
+} // ReadITG3200Gyro
+
+uint8 ReadByteITG3200(uint8 a) {
+    static uint8 d;
+
+    I2CGYRO.start();
+    if ( I2CGYRO.write(ITG3200_W) != I2C_ACK ) goto SGerror;
+    if ( I2CGYRO.write(a) != I2C_ACK ) goto SGerror;
+
+    I2CGYRO.start();
+    if ( I2CGYRO.write(ITG3200_R) != I2C_ACK ) goto SGerror;
+    d = I2CGYRO.read(I2C_NACK);
+    I2CGYRO.stop();
+
+    return ( d );
+
+SGerror:
+    I2CGYRO.stop();
+    // GYRO FAILURE - FATAL
+    Stats[GyroFailS]++;
+    F.GyroFailure = true;
+    return (I2C_NACK);
+} // ReadByteITG3200
+
+void WriteByteITG3200(uint8 a, uint8 d) {
+    I2CGYRO.start();    // restart
+    if ( I2CGYRO.write(ITG3200_W) != I2C_ACK ) goto SGerror;
+    if ( I2CGYRO.write(a) != I2C_ACK ) goto SGerror;
+    if ( I2CGYRO.write(d) != I2C_ACK ) goto SGerror;
+    I2CGYRO.stop();
+    return;
+
+SGerror:
+    I2CGYRO.stop();
+    // GYRO FAILURE - FATAL
+    Stats[GyroFailS]++;
+    F.GyroFailure = true;
+    return;
+} // WriteByteITG3200
+
+void InitITG3200Gyro(void) {
+    F.GyroFailure = false; // reset optimistically!
+
+    WriteByteITG3200(ITG3200_PWR_M, 0x80);    // Reset to defaults
+    WriteByteITG3200(ITG3200_SMPL, 0x00);     // continuous update
+    WriteByteITG3200(ITG3200_DLPF, 0x19);     // 188Hz, 2000deg/S
+    WriteByteITG3200(ITG3200_INT_C, 0x00);    // no interrupts
+    WriteByteITG3200(ITG3200_PWR_M, 0x01);    // X Gyro as Clock Ref.
+
+    Delay1mS(50);
+
+    ReadITG3200Gyro();
+
+} // InitITG3200Gyro
+
+void ITG3200Test(void) {
+    static uint8 MyID, SMPLRT_DIV, DLPF_FS, PWR_MGM;
+    static int16 TEMP,GYRO_X, GYRO_Y, GYRO_Z;
+
+    MyID = ReadByteITG3200(ITG3200_WHO);
+
+    TxString("\tWHO_AM_I  \t0x");
+    TxValH(MyID);
+    TxNextLine();
+    Delay1mS(1);
+    SMPLRT_DIV = ReadByteITG3200(ITG3200_SMPL);
+    DLPF_FS = ReadByteITG3200(ITG3200_DLPF);
+    TEMP = (int16)ReadByteITG3200(ITG3200_TMP_H)<<8 | ReadByteITG3200(ITG3200_TMP_L);
+    GYRO_X = (int16)ReadByteITG3200(ITG3200_GX_H)<<8 | ReadByteITG3200(ITG3200_GX_L);
+    GYRO_Y = (int16)ReadByteITG3200(ITG3200_GY_H)<<8 | ReadByteITG3200(ITG3200_GY_L);
+    GYRO_Z = (int16)ReadByteITG3200(ITG3200_GZ_H)<<8 | ReadByteITG3200(ITG3200_GZ_L);
+    PWR_MGM = ReadByteITG3200(ITG3200_PWR_M);
+
+    ITG3200Temperature = 35.0 + ((TEMP + 13200.0 ) / 280.0);
+
+    TxString("\tSMPLRT_DIV\t");
+    TxVal32( SMPLRT_DIV,0,0);
+    TxNextLine();
+    TxString("\tDLPF      \t");
+    TxVal32( DLPF_FS & 7,0,0 );
+    TxString(" FS         \t");
+    TxVal32( (DLPF_FS>>3)&3, 0, 0);
+    TxNextLine();
+    TxString("\tTEMP      \t");
+    TxVal32( TEMP, 0, 0);
+    TxNextLine();
+    TxString("\tGYRO_X    \t");
+    TxVal32( GYRO_X, 0, 0);
+    TxNextLine();
+    TxString("\tGYRO_Y    \t");
+    TxVal32( GYRO_Y, 0, 0);
+    TxNextLine();
+    TxString("\tGYRO_Z    \t");
+    TxVal32( GYRO_Z, 0, 0);
+    TxNextLine();
+    TxString("\tPWR_MGM   \t0x");
+    TxValH( PWR_MGM );
+    TxNextLine();
+
+    TxNextLine();
+
+} // ITG3200Test
+
+boolean ITG3200GyroActive(void) {
+    I2CGYRO.start();
+    F.GyroFailure = I2CGYRO.write(ITG3200_ID) != I2C_ACK;
+    I2CGYRO.stop();
+    
+    if ( !F.GyroFailure )
+        TrackMinI2CRate(400000);
+
+    return ( !F.GyroFailure );
+
+} // ITG3200GyroActive
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/harness.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,111 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+void UpdateRTC(void);
+void InitHarness(void);
+
+LocalFileSystem Flash("local");
+
+// connections to ARM
+                                        // 1 GND
+                                        // 2 4.5-9V
+                                        // 3 VBat
+                                        // 4 NReset
+                                        
+//SPI SPI0(p5, p6, p7);                 // 5 SPI MOSI, 6 SPI MOSO, 7 SPI CLK
+//DigitalOut SPICS(p8);                 // 8
+SDFileSystem SDCard(p5, p6, p7, p8, "SDCard");
+                                        
+//I2C I2C1(p9, p10);                    // 9 Tx / I2C SDA, 10 Rx / I2C SCL
+SerialBuffered TelemetrySerial(p9, p10);
+DigitalIn Armed(p11);                   // 11 SPI MOSI
+DigitalOut PWMCamPitch(p12);            // 12 SPI MOSO
+                                        
+Serial GPSSerial(p13, p14);             // 13 Tx1 / SPI CLK, 14 Rx1
+
+AnalogIn PitchADC(p15);                 // 15 AN0
+AnalogIn RollADC(p16);                  // 16 AN1
+AnalogIn YawADC(p18);                   // 17 AN2 (has DAC capability)
+
+AnalogIn RangefinderADC(p17);           // 18 AN3
+AnalogIn BatteryCurrentADC(p19);        // 19 AN4
+AnalogIn BatteryVoltsADC(p20);          // 20 AN5 
+
+PwmOut Out0(p21);                       // 21
+PwmOut Out1(p22);                       // 22
+PwmOut Out2(p23);                       // 23
+PwmOut Out3(p24);                       // 24
+
+//PwmOut Out4(p25);                       // 25
+//PwmOut Out5(p26);                       // 26
+
+DigitalOut DebugPin(p25);                  // 25
+
+I2C I2C0(p28, p27);                     // 27, 28
+
+DigitalIn RCIn(p29);                    // 29 CAN
+DigitalOut PWMCamRoll(p30);             // 30 CAN 
+
+//Serial TelemetrySerial(USBTX, USBRX);   
+                                        // 31 USB +, 32 USB -
+                                        // 34 -37 Ethernet
+                                        // 38 IF +
+                                        // 39 IF -
+                                        // 40 3.3V Out 
+                
+// order L-R end of card                        
+DigitalOut BlueLED(LED1);
+DigitalOut GreenLED(LED2);
+DigitalOut RedLED(LED3);
+DigitalOut YellowLED(LED4);
+
+InterruptIn RCInterrupt(p29);
+
+char RTCString[32], RTCLogfile[32];
+struct tm* RTCTime;
+
+void UpdateRTC(void)
+{
+    time_t s = time(NULL);
+    RTCTime = localtime(&s);
+    strftime(RTCString, 32, "%a %b %d %H:%M:%S %Y", RTCTime );   
+} // UpdateRTCString
+
+void InitHarness(void){
+
+    I2C0.frequency(I2C_MAX_RATE_HZ);
+  
+    TelemetrySerial.baud(115200);
+    TelemetrySerial.set_tx_buffer_size(512);  
+
+    GPSSerial.baud(115200); // reduce baud rate to lighten interrupt traffic?
+    
+    PWMCamRoll.write(false);
+    PWMCamPitch.write(false);
+    
+    Armed.mode(PullUp);
+
+    CheckSDCardValid();
+    
+    UpdateRTC();
+
+} // InitHarness
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/i2c.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,163 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+uint32 MinI2CRate = I2C_MAX_RATE_HZ;
+
+void TrackMinI2CRate(uint32 r) {
+ if ( r < MinI2CRate )
+    MinI2CRate = r;
+} // TrackMinI2CRate
+
+void ShowI2CDeviceName(uint8 d)
+{
+    TxChar(' ');
+    switch ( d  ) {
+    case ADXL345_ID: TxString("ADXL345 Acc"); break;
+    case ITG3200_ID: TxString("ITG3200 Gyro"); break;
+    case HMC5843_ID: TxString("HMC5843 Magnetometer"); break;
+    case HMC6352_ID: TxString("HMC6352 Compass"); break;
+    case ADS7823_ID: TxString("ADS7823 ADC"); break;
+    case MCP4725_ID: TxString("MCP4725 DAC"); break;
+    case BOSCH_ID: TxString("Bosch Baro"); break;
+    case TMP100_ID: TxString("TMP100 Temp"); break;
+    case PCA9551_ID: TxString("PCA9551 LED");break;
+    case LISL_ID: TxString("LIS3L Acc"); break;
+    default: break;
+    } // switch
+    TxChar(' ');
+
+} // ShowI2CDeviceName
+
+uint8 ScanI2CBus(void) {
+    uint8 s;
+    uint8 d;
+
+    d = 0;
+
+    TxString("Buss 0\r\n");
+    for ( s = 0x10 ; s <= 0xf6 ; s += 2 ) {
+        I2C0.start();
+        if ( I2C0.write(s) == I2C_ACK ) {
+            d++;
+            TxString("\t0x");
+            TxValH(s);
+            ShowI2CDeviceName( s );
+            TxNextLine();
+        }
+        I2C0.stop();
+
+        Delay1mS(2);
+    }
+    
+    /* 
+    TxString("Buss 1\r\n");
+    for ( s = 0x10 ; s <= 0xf6 ; s += 2 ) {
+        I2C1.start();
+        if ( I2C1.write(s) == I2C_ACK ) {
+            d++;
+            TxString("\t0x");
+            TxValH(s);
+            TxNextLine();
+        }
+        I2C1.stop();
+
+        Delay1mS(2);
+    }
+    */
+
+    PCA9551Test();
+
+    return(d);
+} // ScanI2CBus
+
+void ProgramSlaveAddress(uint8 addr) {
+    static uint8 s;
+
+    for (s = 0x10 ; s < 0xf0 ; s += 2 ) {
+        I2CESC.start();
+        if ( I2CESC.read(s) == I2C_ACK )
+            if ( s == addr ) {   // ESC is already programmed OK
+                I2CESC.stop();
+                TxString("\tESC at SLA 0x");
+                TxValH(addr);
+                TxString(" is already programmed OK\r\n");
+                return;
+            } else {
+                if ( I2CESC.read(0x87) == I2C_ACK ) // select register 0x07
+                    if ( I2CESC.write( addr ) == I2C_ACK ) { // new slave address
+                        I2CESC.stop();
+                        TxString("\tESC at SLA 0x");
+                        TxValH(s);
+                        TxString(" reprogrammed to SLA 0x");
+                        TxValH(addr);
+                        TxNextLine();
+                        return;
+                    }
+            }
+        I2CESC.stop();
+    }
+    TxString("\tESC at SLA 0x");
+    TxValH(addr);
+    TxString(" no response - check cabling and pullup resistors!\r\n");
+} // ProgramSlaveAddress
+
+boolean CheckESCBus(void) {
+    return ( true );
+} // CheckESCBus
+
+void ConfigureESCs(void) {
+    int8 m;
+
+    if ( (int8)P[ESCType] == ESCYGEI2C ) {
+        TxString("\r\nProgram YGE ESCs\r\n");
+        for ( m = 0 ; m < NoOfI2CESCOutputs ; m++ ) {
+            TxString("Connect ONLY ");
+            switch ( m ) {
+#ifdef HEXACOPTER
+                    not yet!
+#else
+                case 0 :
+                    TxString("Front");
+                    break;
+                case 1 :
+                    TxString("Back");
+                    break;
+                case 2 :
+                    TxString("Right");
+                    break;
+                case 3 :
+                    TxString("Left");
+                    break;
+#endif // HEXACOPTER
+            }
+            TxString(" ESC, then press any key \r\n");
+            while ( PollRxChar() != 'x' ); // UAVPSet uses 'x' for any key button
+            //    TxString("\r\n");
+            ProgramSlaveAddress( 0x62 + ( m*2 ));
+        }
+        TxString("\r\nConnect ALL ESCs and power-cycle the Quadrocopter\r\n");
+    } else
+        TxString("\r\nYGEI2C not selected as ESC?\r\n");
+} // ConfigureESCs
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ir.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,85 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+// IR Sensors ( Scheme from "Leveller" Autopilot ~2005 )
+
+void GetIRAttitude(void);
+void TrackIRMaxMin(real32);
+void InitIRSensors(void);
+
+// FMA Roll/Pitch connector Pin1 Gnd, Pin 2 3.3V, Pin3 -Pitch, Pin4 Roll.
+// FMA Z-Axis     connector Pin1 Gnd, Pin 2 3.3V, Pin3 Z , Pin4 Unused.
+// DIYDrones      connector Pin1 Gnd, Pin 2 3.3V, Pin3 Z, Pin4 -Pitch, Pin5 Roll.
+
+real32 IR[3], IRMax, IRMin, IRSwing;
+
+
+void TrackIRMaxMin(real32 m) {
+    if ( m > IRMax ) IRMax = m;
+    else
+        if ( m < IRMin ) IRMin = m;
+        
+    IRSwing = Max( IRSwing, fabs(m) );
+    IRSwing -= 0.00001; // zzz
+
+} // TrackIRMaxMin
+
+void GetIRAttitude() {
+    #define IR_NEUTRAL 1.0
+    static uint8 i;
+
+    if ( GyroType == IRSensors ) {
+    
+    IR[Pitch] = -PitchADC.read() * 2.0 - IR_NEUTRAL;
+    IR[Roll] = RollADC.read() * 2.0 - IR_NEUTRAL;
+    IR[Yaw] = YawADC.read() * 2.0 - IR_NEUTRAL;
+
+    for ( i = 0; i < (uint8)3; i++ )
+        TrackIRMaxMin(IR[i]);
+
+    for ( i = 0; i < (uint8)2; i++ )
+        Angle[i] = asin ( Limit( IR[i] / IRSwing, -1.0, 1.0 ) );
+
+    Angle[Yaw] = 0.0;
+    Rate[Yaw] = 0.0;
+    
+    }
+
+} // GetIRAttitude
+
+void InitIRSensors() {
+    static uint8 i;
+
+    LEDYellow_ON;
+    IRSwing = 0.5;
+
+    IRMax = -1.0;
+    IRMin= 1.0;
+
+    for ( i = 0; i < 20; i++ ) {
+        GetIRAttitude();
+        Delay1mS(100);
+    }
+
+    LEDYellow_OFF;
+
+} // InitIRSensors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/irq.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,190 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+// Interrupt Routines
+
+
+const int16 MIN_PPM_SYNC_PAUSE = 2400;      // uS
+
+// no less than 1500
+
+extern void InitTimersAndInterrupts(void);
+
+void enableTxIrq0(void);
+void disableTxIrq0(void);
+void enableTxIrq1(void);
+void disableTxIrq1(void);
+
+void RCISR(void);
+void RCNullISR(void);
+void RCTimeoutISR(void);
+void CamPWMOnISR(void);
+void CamRollPWMOffISR(void);
+void CamPitchPWMOffISR(void);
+void TelemetryInISR(void);
+void GPSInISR(void);
+
+Timer timer;
+Timeout CamRollTimeout, CamPitchTimeout;
+Ticker CameraTicker;
+Timeout RCTimeout;
+
+uint32    mS[CompassUpdate + 1];
+
+uint32    PrevEdge, CurrEdge;
+uint8     Intersection, PrevPattern, CurrPattern;
+uint32    Width;
+int16     PPM[MAX_CONTROLS];
+int8      PPM_Index;
+int24     PauseTime;
+uint8     RxState;
+int8      State, FailState;
+int8      SignalCount;
+uint16    RCGlitches;
+int16     PWMCycles = 0;
+
+void enableTxIrq0(void) {
+    LPC_UART0->IER |= 0x0002;
+} // enableTxIrq0
+
+void disableTxIrq0(void) {
+    LPC_UART0->IER &= ~0x0002;
+} // disableTxIrq0
+
+void enableTxIrq1(void) {
+    LPC_UART1->IER |= 0x0002;
+} // enableTxIrq1
+
+void disableTxIrq1(void) {
+    LPC_UART1->IER &= ~0x0002;
+}  // disableTxIrq1
+
+void InitTimersAndInterrupts(void) {
+    static int8 i;
+
+    timer.start();
+
+    GPSSerial.attach(GPSInISR, GPSSerial.RxIrq);
+
+    InitTelemetryPacket();
+    //TelemetrySerial.attach(TelemetryInISR, TelemetrySerial.RxIrq);
+
+    RCPositiveEdge = true;
+
+    RCTimeout.attach_us(& RCTimeoutISR, 50000);
+
+#ifdef SOFTWARE_CAM_PWM
+    CameraTicker.attach_us(&CamPWMOnISR, 22500);
+#endif // SOFTWARE_CAM_PWM
+
+    for (i = Clock; i<= CompassUpdate; i++)
+        mS[i] = 0;
+
+} // InitTimersAndInterrupts
+
+void RCISR(void) {
+    CurrEdge = timer.read_us();
+
+    Width = CurrEdge - PrevEdge;
+    PrevEdge = CurrEdge;
+
+    if ( Width > MIN_PPM_SYNC_PAUSE ) {  // A pause  > 5ms
+        PPM_Index = 0;                        // Sync pulse detected - next CH is CH1
+        F.RCFrameOK = true;
+        F.RCNewValues = false;
+        PauseTime = Width;
+    } else
+        if (PPM_Index < RC_CONTROLS) { // Width in 1us ticks.
+            if ( ( Width >= RC_MIN_WIDTH_US ) && ( Width <= RC_MAX_WIDTH_US ) )
+                PPM[PPM_Index] = Width - 1000;
+            else {
+                // preserve old value i.e. default hold
+                RCGlitches++;
+                F.RCFrameOK = false;
+            }
+
+            PPM_Index++;
+            // MUST demand rock solid RC frames for autonomous functions not
+            // to be cancelled by noise-generated partially correct frames
+            if ( PPM_Index == RC_CONTROLS ) {
+                if ( F.RCFrameOK ) {
+                    F.RCNewValues = true;
+                    SignalCount++;
+                } else {
+                    F.RCNewValues = false;
+                    SignalCount -= RC_GOOD_RATIO;
+                }
+
+                SignalCount = Limit(SignalCount, -RC_GOOD_BUCKET_MAX, RC_GOOD_BUCKET_MAX);
+                F.Signal = SignalCount > 0;
+
+                if ( F.Signal )
+                    mS[LastValidRx] = timer.read_ms();
+
+                RCTimeout.attach_us(& RCTimeoutISR, RC_SIGNAL_TIMEOUT_MS*1000);
+            }
+        }
+
+} // RCISR
+
+void RCNullISR(void) {
+// discard edge
+} // RCNullISR
+
+void CamPWMOnISR(void) {
+
+    PWMCamRoll.write(true);
+    CamRollTimeout.attach_us(&CamRollPWMOffISR, CamRollPulseWidth);
+    PWMCamPitch.write(true);
+    CamPitchTimeout.attach_us(&CamPitchPWMOffISR, CamPitchPulseWidth);
+
+} // CamPWMOnISR
+
+void CamRollPWMOffISR(void) {
+
+    PWMCamRoll.write(false);
+    CamRollTimeout.detach();
+
+} // CamRollPWMOffISR
+
+void CamPitchPWMOffISR(void) {
+
+    PWMCamPitch.write(false);
+    CamPitchTimeout.detach();
+
+} // CamPitchPWMOffISR
+
+void RCTimeoutISR(void) {
+    if ( F.Signal ) {
+        F.Signal = false;
+        SignalCount = -RC_GOOD_BUCKET_MAX;
+    }
+} // RCTimeoutISR
+
+void GPSInISR(void) {
+    RxGPSPacket( GPSSerial.getc());
+} // GPSInISR
+
+void TelemetryInISR(void) {
+    RxTelemetryPacket(TelemetrySerial.getc());
+} // TelemetryInISR
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/leds.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,265 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+void SendLEDs(void);
+void SaveLEDs(void);
+void RestoreLEDs(void);
+void LEDsOn(uint16);
+void LEDsOff(uint16);
+void LEDChaser(void);
+
+void PCA9551Test(void);
+void WritePCA9551(uint8);
+boolean IsPCA9551Active(void);
+
+void DoLEDs(void);
+void PowerOutput(int8);
+void LEDsAndBuzzer(void);
+void InitLEDs(void);
+
+uint16 LEDShadow, SavedLEDs, LEDPattern = 0;
+uint16 PrevLEDShadow;
+uint8 PrevPCA9551LEDShadow;
+
+boolean PrevHolding = false;
+const uint16 LEDChase[8] = {
+    YellowM,
+    RedM,
+    GreenM,
+    BlueM, 
+    DRV1M,
+    DRV3M,
+    DRV2M,
+    DRV0M
+};
+
+void WritePCA9551(uint8 S) {
+    const uint8 M = 0; // On
+    //  const uint8 M = 2; // PWM0 rate
+    //  const uint8 M = 3; // PWM1 rate
+
+    const uint8 LOFF = 1; // High impedance
+    static uint8 L03, L47, i;
+
+    L03 = L47 = 0;
+    for ( i = 0; i < 4; i++ ) {
+        L03 <<= 2;
+        if ( S & 0x80 )
+            L03 |= M;
+        else
+            L03 |= LOFF;
+        S  <<= 1;
+    }
+
+    for ( i = 0; i <4; i++ ) {
+        L47 <<= 2;
+        if ( S & 0x80 )
+            L47 |= M;
+        else
+            L47 |= LOFF;
+        S  <<= 1;
+    }
+
+    I2CLED.start();
+    I2CLED.write(PCA9551_ID);
+    I2CLED.write(0x15);
+    I2CLED.write(L03);
+    I2CLED.write(L47);
+    I2CLED.stop();
+
+} // WritePCA9551
+
+void SendLEDs(void) { // 39.3 uS @ 40MHz
+    static uint8 PCA9551LEDShadow;
+
+    if ( LEDShadow != PrevLEDShadow ) {
+
+        BlueLED = LEDShadow & BlueM;
+        RedLED = LEDShadow & RedM;
+        GreenLED = LEDShadow & GreenM;
+        YellowLED = LEDShadow & YellowM;
+
+        PCA9551LEDShadow = uint8(LEDShadow & 0x00ff);
+
+        if ( F.UsingLEDDriver && ( PCA9551LEDShadow != PrevPCA9551LEDShadow ) ) {
+            WritePCA9551(PCA9551LEDShadow);
+            PrevPCA9551LEDShadow = PCA9551LEDShadow;
+        }
+
+        PrevLEDShadow = LEDShadow;
+    }
+
+} // SendLEDs
+
+
+void SaveLEDs(void) { // one level only
+    SavedLEDs = LEDShadow;
+} // SaveLEDs
+
+void RestoreLEDs(void) {
+    LEDShadow = SavedLEDs;
+    SendLEDs();
+} // RestoreLEDs
+
+void LEDsOn(uint16 l) {
+    LEDShadow |= l;
+    SendLEDs();
+} // LEDsOn
+
+void LEDsOff(uint16 l) {
+    LEDShadow &= ~l;
+    SendLEDs();
+} // LEDsOff
+
+void LEDChaser(void) {
+#define LED_NO  (uint8)6    // skip buzzer
+//#define LED_NO  (uint8)7    // all LEDs
+
+    if ( mSClock() > mS[LEDChaserUpdate] ) {
+        if ( F.HoldingAlt ) {
+            LEDShadow ^= LEDChase[LEDPattern];
+            if ( LEDPattern < LED_NO ) LEDPattern++;
+            else LEDPattern = 0;
+            LEDShadow |= LEDChase[LEDPattern];
+            SendLEDs();
+        } else {
+            LEDShadow = SavedLEDs;
+            SendLEDs();
+        }
+
+        mS[LEDChaserUpdate] = mSClock() + 50;
+    }
+} // LEDChaser
+
+void DoLEDs(void) {
+    if ( F.AccelerationsValid  ) LEDYellow_ON;
+    else LEDYellow_OFF;
+
+    if ( F.Signal ) {
+        LEDRed_OFF;
+        LEDGreen_ON;
+    } else {
+        LEDGreen_OFF;
+        LEDRed_ON;
+    }
+} // DoLEDs
+
+void PowerOutput(int8 d) {
+    int8 s;
+    uint16 m;
+
+    m = 1 << d;
+    for ( s=0; s < 10; s++ ) { // 10 flashes (count MUST be even!)
+        LEDShadow ^= m;
+        SendLEDs();
+        Delay1mS(50);
+    }
+} // PowerOutput
+
+void LEDsAndBuzzer(void) {
+    int8 s, m;
+    uint16 mask, LEDSave;
+
+    LEDSave = LEDShadow;
+    LEDShadow  = 0;
+    SendLEDs();
+
+    TxString("\r\nOutput test\r\n");
+    TxString("Sequence Drv0/Buzz, Drv1, Drv2, Drv3, Aux0, Aux1, Aux2, Aux3, Y, R, G, B\r\n");
+    mask = (uint8)1;
+    for ( m = 1; m <= 12; m++ ) {        
+        for ( s = 0; s < 10; s++ ) { // 10 flashes (count MUST be even!)
+            LEDShadow ^= mask;
+            SendLEDs();
+            Delay1mS(100);
+        }
+        mask <<= 1;
+    }
+    LEDShadow  = LEDSave;
+    SendLEDs();
+    TxString("Test Finished\r\n");
+} // LEDsAndBuzzer
+
+//______________________________________________________________________________________________
+
+// LED Driver
+
+void PCA9551Test(void) {
+    static char b[8], i, r;
+
+    TxString("\r\nPCA9551Test\r\n");
+
+    I2CLED.start();
+    I2CGYRO.write(PCA9551_ID);
+    I2CGYRO.write(0x11);
+    I2CLED.stop();
+
+    I2CLED.read(PCA9551_ID, b, 7);
+
+    TxString("0:\t0b");
+    TxBin8(b[6]);
+    TxNextLine();
+    for (i = 0; i <6; i++ ) {
+        TxVal32(i+1, 0,0);
+        TxString(":\t0b");
+        TxBin8(b[i]);
+        TxNextLine();
+    }
+    TxNextLine();
+} // PCA9551Test
+
+boolean IsPCA9551Active(void) {
+
+    const char b[7] = {0x11,0x25,0x80,0x25,0x80,0x00,0x00}; // Period 1Sec., PWM 50%, ON
+
+    F.UsingLEDDriver = true; // optimistic
+
+    I2CLED.start();
+    if ( I2CGYRO.write(PCA9551_ID) != I2C_ACK ) goto LError;
+    I2CLED.stop();
+
+    I2CLED.write(PCA9551_ID, b, 7);
+    
+    TrackMinI2CRate(400000);
+
+    return ( true );
+
+LError:
+    F.UsingLEDDriver = false;
+    return (  F.UsingLEDDriver );
+
+} //IsPCA9551Active
+
+void InitLEDs(void) {
+
+    boolean r;
+
+    r = IsPCA9551Active();
+       
+    LEDShadow = SavedLEDs = LEDPattern = 0;
+    PrevLEDShadow = 0x0fff;
+
+    PrevPCA9551LEDShadow = 0;
+    WritePCA9551( PrevPCA9551LEDShadow );
+
+} // InitLEDs
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/math.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,118 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+int16 SRS16(int16, uint8);
+int32 SRS32(int32, uint8);
+real32 Make2Pi(real32);
+real32 MakePi(real32);
+int16 Table16(int16, const int16 *);
+
+real32 VDot(real32 v1[3], real32 v2[3]);
+void VCross(real32 VOut[3], real32 v1[3], real32 v2[3]);
+void VScale(real32 VOut[3], real32 v[3], real32 s);
+void VAdd(real32 VOut[3],real32 v1[3], real32 v2[3]);
+void VSub(real32 VOut[3],real32 v1[3], real32 v2[3]);
+
+int16 SRS16(int16 x, uint8 s) {
+    static i16u Temp;
+
+    if ( s == (uint8)8 ) {
+        Temp.i16 = x;
+        return( (int16) Temp.i1 );
+    } else
+        return((x<0) ? -((-x)>>s) : (x>>s));
+} // SRS16
+
+int32 SRS32(int32 x, uint8 s) {
+    static i32u Temp;
+
+    if ( s == (uint8)8 ) {
+        Temp.i32 = x;
+        return( (int32)Temp.i3_1 );
+    } else
+        return((x<0) ? -((-x)>>s) : (x>>s));
+} // SRS32
+
+real32 Make2Pi(real32 A) {
+    while ( A < 0 ) A += TWOPI;
+    while ( A >= TWOPI ) A -= TWOPI;
+    return( A );
+} // Make2Pi
+
+real32 MakePi(real32 A) {
+    while ( A < -PI ) A += TWOPI;
+    while ( A >= PI ) A -= TWOPI;
+    return( A );
+} // MakePi
+
+int16 Table16(int16 Val, const int16 *T) {
+    static uint8 Index,Offset;
+    static int16 Temp, Low, High;
+
+    Index = (uint8) (Val >> 4);
+    Offset = (uint8) (Val & 0x0f);
+    Low = T[Index];
+    High = T[++Index];
+    Temp = (High-Low) * Offset;
+
+    return( Low + SRS16(Temp, 4) );
+} // Table16
+
+
+real32 VDot(real32 v1[3], real32 v2[3]) {
+    static real32 op;
+    static uint8 i;
+
+    op = 0.0;
+    for ( i = 0; i < (uint8)3; i++ )
+        op += v1[i] * v2[i];
+
+    return op;
+} // VDot
+
+void VCross(real32 VOut[3], real32 v1[3], real32 v2[3]) {
+    VOut[0]= (v1[1] * v2[2]) - (v1[2] * v2[1]);
+    VOut[1]= (v1[2] * v2[0]) - (v1[0] * v2[2]);
+    VOut[2]= (v1[0] * v2[1]) - (v1[1] * v2[0]);
+} // VCross
+
+void VScale(real32 VOut[3], real32 v[3], real32 s) {
+    static uint8 i;
+
+    for ( i = 0; i < (uint8)3; i++ )
+        VOut[i] = v[i] * s;
+} // VScale
+
+void VAdd(real32 VOut[3],real32 v1[3], real32 v2[3]) {
+    static uint8 i;
+
+    for ( i = 0; i < (uint8)3; i++ )
+        VOut[i] = v1[i] + v2[i];
+} // VAdd
+
+void VSub(real32 VOut[3],real32 v1[3], real32 v2[3]) {
+    static uint8 i;
+
+    for ( i = 0; i < (uint8)3; i++ )
+        VOut[i] = v1[i] - v2[i];
+} // VSub
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/e2ac27c8e93e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menu.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,525 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+void ShowPrompt(void);
+void ShowRxSetup(void);
+void ShowSetup(boolean);
+uint8 MakeUpper(uint8);
+void ProcessCommand(void);
+
+const uint8 SerHello[] = "UAVXArm "
+                         " Copyright 2008 G.K. Egan & 2007 W. Mahringer\r\n"
+                         "This is FREE SOFTWARE and comes with ABSOLUTELY NO WARRANTY "
+                         "see http://www.gnu.org/licenses/!\r\n";
+const uint8 SerHelp[] = "\r\nCommands:\r\n"
+                        "A..Attitude test\r\n"
+                        "C..Compass test\r\n"
+                        "D..Load default parameter set\r\n"
+                        "G..GPS test\r\n"
+                        "H..Barometer/Rangefinder test\r\n"
+                        "I..I2C bus scan\r\n"
+                        "K..Calibrate compass scan\r\n"
+//    "M..Modify parameters\r\n"
+                        "P..Rx test\r\n"
+                        "S..Setup\r\n"
+                        "T..All LEDs and buzzer test\r\n"
+                        "V..Battery test\r\n"
+                        "X..Flight stats\r\n"
+                        "Y..Program YGE I2C ESC\r\n"
+                        "1-8..Individual LED/buzzer test\r\n"; // last line must be in this form for UAVPSet
+
+const uint8 RxChMnem[] = "TAERG12";
+
+uint8 MakeUpper(uint8 ch) {
+    if ( ( ch >='a') && ( ch <='z' ) )
+        ch = (ch - 'a') + 'A';
+
+    return (ch);
+} // MakeUpper
+
+void ShowPrompt(void) {
+    TxString("\r\n>");
+} // ShowPrompt
+
+void ShowRxSetup(void) {
+    if ( F.UsingSerialPPM )
+        if ( PPMPosPolarity[P[TxRxType]] )
+            TxString("Serial PPM frame (Positive Polarity)");
+        else
+            TxString("Serial PPM frame (Negative Polarity)");
+    else
+        TxString("Odd Rx Channels PPM");
+} // ShowRxSetup
+
+void ShowSetup(boolean h) {
+    int8 i;
+
+    TxNextLine();
+    if ( h )
+        ParamSet = 1;
+
+    TxString(SerHello);
+
+    UpdateRTC();
+    i = 0;
+    while ( RTCString[i] != NULL )
+        TxChar(RTCString[i++]);
+    TxNextLine();
+
+    TxString("Clock: 92MHz LPC1768 (mbed)\r\n");
+
+    TxString("Aircraft: ");
+    switch ( UAVXAirframe ) {
+        case QuadAF:
+            TxString("QUADROCOPTER\r\n");
+            break;
+        case TriAF:
+            TxString("TRICOPTER\r\n");
+            break;
+        case VTAF:
+            TxString("VTCOPTER\r\n");
+            break;
+        case HeliAF:
+            TxString("HELICOPTER\r\n");
+            break;
+        case ElevAF:
+            TxString("FLYING WING\r\n");
+            break;
+        case AilAF:
+            TxString("AILERON\r\n");
+            break;
+        default:
+            TxString("UNKNOWN\r\n");
+    }
+
+    if ( F.CompassValid ) {
+        TxString("Compass: ");
+        ShowCompassType();
+        TxString(" ( offset  ");
+        TxVal32((int16)P[CompassOffsetQtr] * 90,0,0);
+        TxString("deg. )\r\n");
+    }
+
+    TxString("Baro: ");
+    ShowBaroType();
+
+    TxString("Accelerometers: ");
+    ShowAccType();
+    TxNextLine();
+
+    TxString("Gyros: ");
+    ShowGyroType();
+    TxNextLine();
+
+    TxString("Motor ESCs: ");
+    switch ( P[ESCType] ) {
+        case ESCPPM:
+            TxString("PPM ");
+            break;
+        case ESCHolger:
+            TxString("Holger I2C {");
+            break;
+        case ESCX3D:
+            TxString("X-3D I2C {");
+            break;
+        case ESCYGEI2C:
+            TxString("YGE I2C {");
+            break;
+    }
+
+    if ( P[ESCType] != ESCPPM ) {
+        for ( i = 0; i < NoOfI2CESCOutputs; i++ )
+            if ( ESCI2CFail[i] )
+                TxString(" Fail");
+            else
+                TxString(" OK");
+        TxString(" }");
+    }
+    TxNextLine();
+    
+    if ( F.HaveBatterySensor )
+         TxString("External Volt/Amp Sensor Fitted\r\n");
+#ifdef RX6CH
+    TxString("6 CHANNEL VERSION - 5 ACTIVE CHANNELS ONLY\r\n");
+#endif // RX6CH
+
+    TxString("Tx/Rx: ");
+
+    switch ( P[TxRxType] ) {
+        case FutabaCh3:
+            TxString("Futaba Th 3 {");
+            break;
+        case FutabaCh2:
+            TxString("Futaba Th 2 {");
+            break;
+        case FutabaDM8:
+            TxString("Futaba DM8 & AR7000 {");
+            break;
+        case JRPPM:
+            TxString("JR PPM {");
+            break;
+        case JRDM9:
+            TxString("JR DM9 & AR7000{");
+            break;
+        case JRDXS12:
+            TxString("JR DSX12 & AR7000 {");
+            break;
+        case DX7AR7000:
+            TxString("Spektrum DX7 & AR7000 {");
+            break;
+        case DX7AR6200:
+            TxString("Spektrum DX7 & AR6200 {");
+            break;
+        case CustomTxRx:
+            TxString("Custom {");
+            break;
+        case FutabaCh3_6_7:
+            TxString("Futaba Th 2 Swap 6&7 {");
+            break;
+        case DX7AR6000:
+            TxString("Spektrum DX7 & AR6000 {");
+            break;
+        case DX6iAR6200:
+            TxString("Spektrum DX6i & AR6200 {");
+            break;
+        case FutabaCh3_R617FS:
+            TxString("Futaba Th 3 & R617FS {");
+            break;
+        case GraupnerMX16s:
+            TxString("Graupner MX16s {");
+            break;
+        case DX7aAR7000:
+            TxString("Spektrum DX7a & AR7000 {");
+            break;
+        case FrSkyDJT_D8R:
+            TxString("FrSky DJT & D8R-SP Composite {");
+            break;
+        case ExternalDecoder:
+            TxString("External Decoder {");
+            break;
+        case UnknownTxRx:
+            TxString("UNKNOWN {");
+            break;
+        default:
+            ;
+    }  // switch
+
+    if ( F.UsingSerialPPM )
+        ShowRxSetup();
+    else
+        if ( P[TxRxType] != UnknownTxRx ) {
+            for ( i = 0; i < RC_CONTROLS; i++)
+                TxChar(RxChMnem[RMap[i]]);
+
+            TxString("} connect {");
+
+            for ( i = 0; i < RC_CONTROLS; i+=2) {
+                TxChar(RxChMnem[RMap[i]]);
+                TxChar(' ');
+            }
+        }
+    TxChar('}');
+    if (( P[TxRxType] == DX7AR6200 ) || ( P[TxRxType] == DX6iAR6200))
+        TxString(" Mix Rudder to Aux1/Flaps ");
+    if ( F.UsingTxMode2 )
+        TxString(" Tx Mode 2");
+    else
+        TxString(" Tx Mode 1");
+    TxNextLine();
+
+    TxString("Selected parameter set: "); // must be exactly this string as UAVPSet expects it
+    TxChar('0' + ParamSet);
+    TxNextLine();
+
+#ifdef MULTICOPTER
+    TxString("Forward Flight: ");
+    TxVal32((int16)Orientation * 75L, 1, 0);
+    TxString("deg CW from K1 motor(s)\r\n");
+#endif // MULTICOPTER
+
+    if ( F.UsingAngleControl )
+        TxString("\tSticks control roll/pitch angle directly\r\n");
+    else
+        TxString("\tSticks control rate of change of roll/pitch angle\r\n");
+
+    if ( F.UsingRTHAutoDescend )
+        TxString("\tAuto descend ENABLED\r\n");
+    else
+        TxString("\tAuto descend disabled\r\n");
+
+    if ( F.AllowTurnToWP )
+        TxString("\tTurn toward Way Point\r\n");
+    else
+        TxString("\tHold heading\r\n");
+
+    if ( F.AllowNavAltitudeHold )
+        TxString("\tAllow Nav altitude hold\r\n");
+    else
+        TxString("\tWARNING - Manual Nav altitude hold\r\n");
+
+    if ( !F.SDCardValid )
+        TxString("\tSD Card NOT loaded - DISCONNECT power and load card if required.\r\n");
+
+    TxString("\r\nALARM (if any):\r\n");
+    if ( P[TxRxType] == UnknownTxRx )
+        TxString("\tTx/Rx TYPE not set\r\n");
+#ifdef TESTING
+    TxString("\tTEST VERSION - No Motors\r\n");
+#endif // TESTING
+
+    if ( !F.ParametersValid )
+        TxString("\tINVALID flight parameters (PID)!\r\n");
+
+    if ( !F.BaroAltitudeValid )
+        TxString("\tBarometer OFFLINE\r\n");
+    if ( BaroRetries >= BARO_INIT_RETRIES )
+        TxString("\tBaro Init: FAILED\r\n");
+
+    if ( !F.RangefinderAltitudeValid )
+        TxString("\tRangefinder OFFLINE\r\n");
+
+    if ( F.GyroFailure )
+        TxString("\tGyro FAILURE\r\n");
+
+    if ( !F.AccelerationsValid )
+        TxString("\tAccelerometers OFFLINE\r\n");
+
+    if ( !F.CompassValid )
+        TxString("\tCompass OFFLINE\r\n");
+
+    if ( !F.Signal )
+        TxString("\tBad EPAs or Tx switched off?\r\n");
+    if ( Armed && FirstPass )
+        TxString("\tUAVX is armed - DISARM!\r\n");
+
+    if ( F.Navigate || F.ReturnHome )
+        TxString("\tNavigate/RTH is selected - DESELECT!\r\n");
+
+    if ( InitialThrottle >= RC_THRES_START )
+        TxString("\tThrottle may be open - CLOSE!\r\n");
+
+    ShowPrompt();
+} // ShowSetup
+
+void ProcessCommand(void) {
+    static int8  p;
+    static uint8 ch;
+    static int8 d;
+
+    if ( 1 ) {//!Armed.read() ) {
+        ch = PollRxChar();
+        if ( ch != NUL   ) {
+            ch = MakeUpper(ch);
+
+            switch ( ch ) {
+                case 'D':
+                    UseDefaultParameters();
+                    ShowPrompt();
+                    break;
+                case 'L'  :    // List parameters
+                    TxString("\r\nParameter list for set #");    // do not change (UAVPset!)
+                    TxChar('0' + ParamSet);
+                    ReadParameters();
+                    for ( p = 0 ; p < MAX_PARAMETERS; p++ ) {
+                        TxString("\r\nRegister ");
+                        TxValU((uint8)(p+1));
+                        TxString(" = ");
+                        TxValS(P[p]);
+                    }
+                    ShowPrompt();
+                    break;
+                case 'M'  : // modify parameters
+                    // no reprogramming in flight!!!!!!!!!!!!!!!
+                    LEDBlue_ON;
+                    TxString("\r\nRegister ");
+                    p = (uint16)(RxNumU()-1);
+                    // Attempts to block use of old versions of UAVPSet not compatible with UAVX
+                    // assumes parameters are written sequentially from 0..(MAX_PARAMETERS-1)
+
+                    TxString(" = ");
+                    d = RxNumS();
+                    if ( p < MAX_PARAMETERS ) {
+                        // Keep RAM based set up to date.
+                        if ( ParamSet == (uint8)1 ) {
+                            WritePX(p, d);
+                            if ( DefaultParams[p][1] )
+                                WritePX(MAX_PARAMETERS + p, d);
+                        } else {
+                            if ( !DefaultParams[p][1] )
+                                WritePX(MAX_PARAMETERS + p, d);
+                        }
+                        ParametersChanged = true;
+                    }
+                    if ( p < (MAX_PARAMETERS-1) )
+                        F.ParametersValid = false;
+                    else
+                        if ( p == (MAX_PARAMETERS-1) ) {
+                            WritePXImagefile();
+                            F.ParametersValid = true;     // ALL parameters must be written
+                        }
+                    LEDBlue_OFF;
+                    ShowPrompt();
+                    break;
+                case 'N' :    // neutral values
+                    TxString("\r\nNeutral    R:");
+                    TxValS(NewAccNeutral[BF]);
+
+                    TxString("    P:");
+                    TxValS(NewAccNeutral[LR]);
+
+                    TxString("   V:");
+                    TxValS(NewAccNeutral[UD]);
+                    ShowPrompt();
+                    break;
+                case 'Z' : // set Paramset
+                    p = RxNumU();
+                    if ( p != (int8)ParamSet ) {
+                        ParamSet = p;
+                        ParametersChanged = true;
+                        ReadParameters();
+                    }
+                    break;
+                case 'W' :    // comms with UAVXNav utility NOT UAVPSet
+                    UAVXNavCommand();
+                    //ShowPrompt();
+                    break;
+                case 'R':    // receiver values
+                    TxString("\r\nT:");
+                    TxValU(ToPercent(RC[ThrottleRC], RC_MAXIMUM));
+                    TxString(",R:");
+                    TxValS(ToPercent(((RC[RollRC]- RC_NEUTRAL) * 2L), RC_MAXIMUM));
+                    TxString(",P:");
+                    TxValS(ToPercent(((RC[PitchRC]- RC_NEUTRAL) * 2L), RC_MAXIMUM));
+                    TxString(",Y:");
+                    TxValS(ToPercent(((RC[YawRC]- RC_NEUTRAL) * 2L), RC_MAXIMUM));
+                    TxString(",5:");
+                    TxValU(ToPercent(RC[RTHRC], RC_MAXIMUM));
+                    TxString(",6:");
+                    TxValS(ToPercent(((RC[CamPitchRC] - RC_NEUTRAL) * 2L), RC_MAXIMUM));
+                    TxString(",7:");
+                    TxValU(ToPercent(RC[NavGainRC], RC_MAXIMUM));
+                    ShowPrompt();
+                    break;
+                case 'S' :    // show status
+                    ShowSetup(false);
+                    break;
+                case 'X' :    // flight stats
+                    ShowStats();
+                    ShowPrompt();
+                    break;
+                case 'A' :    // linear sensor
+                    AttitudeTest();
+                    ShowPrompt();
+                    break;
+                case 'G':    // GPS
+                    GPSTest();
+                    ShowPrompt();
+                    break;
+                case 'H':    // barometer
+                    BaroTest();
+                    ShowPrompt();
+                    break;
+                case 'I':
+                    TxString("\r\nI2C devices ...\r\n");
+                    TxVal32(ScanI2CBus(),0,0);
+                    TxString(" device(s) found\r\n");
+                    ShowPrompt();
+                    break;
+                case 'P'  :    // Receiver test
+                    ReceiverTest();
+                    ShowPrompt();
+                    break;
+                case 'C'  :    // Compass test
+                    DoCompassTest();
+                    ShowPrompt();
+                    break;
+
+                case 'K'  :    //Calibrate compass
+                    CalibrateCompass();
+                    ShowPrompt();
+                    break;
+
+                case 'Y':    // configure YGE30i EScs
+                    ConfigureESCs();
+                    ShowPrompt();
+                    break;
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                    TxString("\r\nOutput test\r\n");
+                    TxChar(ch);
+                    TxChar(':');
+                    switch ( ch ) {
+                        case '1':
+                            TxString("Aux2");
+                            break;
+                        case '2':
+                            TxString("Blue");
+                            break;
+                        case '3':
+                            TxString("Red");
+                            break;
+                        case '4':
+                            TxString("Green");
+                            break;
+                        case '5':
+                            TxString("Aux1");
+                            break;
+                        case '6':
+                            TxString("Yellow");
+                            break;
+                        case '7':
+                            TxString("Aux3");
+                            break;
+                        case '8':
+                            TxString("Beeper");
+                            break;
+                    }
+                    TxNextLine();
+                    PowerOutput(ch-'1');
+                    ShowPrompt();
+                    break;
+                case 'T':
+                    LEDsAndBuzzer();
+                    ShowPrompt();
+                    break;
+
+                case 'V' :    // Battery test
+                    BatteryTest();
+                    ShowPrompt();
+                    break;
+                case '?'  :  // help
+                    TxString(SerHelp);
+                    ShowPrompt();
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+} // ProcessCommand
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nonvolatile.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,221 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+// transfers to Flash seem to be ~35KByte/Sec
+
+void CheckSDCardValid(void);
+
+void CreateLogfile(void);
+void CloseLogfile(void);
+void TxLogChar(uint8);
+
+void WritePXImagefile(void);
+boolean ReadPXImagefile(void);
+
+int8 ReadPX(uint16);
+int16 Read16PX(uint16);
+int32 Read32PX(uint16);
+void WritePX(uint16, int8);
+void Write16PX(uint16, int16);
+void Write32PX(uint16, int32);
+
+FILE *pxfile = NULL;
+FILE *newpxfile = NULL;
+
+const int PX_LENGTH = 2048;
+int8 PX[PX_LENGTH], PXNew[PX_LENGTH];
+
+void CheckSDCardValid(void) {
+    /*
+        FILE *testfile;
+
+        testfile = fopen("/SDCard/OK", "w");
+        F.SDCardValid = testfile != NULL;
+        if ( F.SDCardValid ) fclose(testfile);
+    */
+    F.SDCardValid =  SDCard.initialise_card() != 0;
+
+
+} // CheckSDCardValid
+
+void WritePXImagefile(void) {
+    static uint16 a;
+    static int32 CheckSum;
+    static int8 v, i;
+
+    UpdateRTC();
+
+    if ( F.PXImageStale ) {
+        if ( F.SDCardValid )
+            newpxfile = fopen("/SDCard/Params.txt", "w");
+        else
+            newpxfile = fopen("/local/Params.txt", "w");
+
+        if ( newpxfile != NULL ) {
+            CheckSum = 0;
+            for ( a = 0; a < PX_LENGTH; a++ ) {
+                v = PX[a];
+                CheckSum += (int32)v;
+                fprintf(newpxfile, "%i \r\n",  v);
+            }
+            fprintf(newpxfile, "%li \r\n ",  -CheckSum );
+
+            i=0;
+            while ( RTCString[i] != 0 )
+                fprintf(newpxfile, "%c", RTCString[i++]);
+            fprintf(newpxfile, "\r\n");
+
+            F.PXImageStale = false;
+            fclose(newpxfile);
+        }
+    }
+
+} // WritePXIMagefile
+
+boolean ReadPXImagefile(void) {
+    static uint16 a;
+    static int8 r;
+    static int32 v, CheckSum;
+    static boolean OK;
+
+    if ( F.SDCardValid )
+        pxfile = fopen("/SDCard/Params.txt", "r");
+    else
+        pxfile = fopen("/local/Params.txt", "r");
+
+
+    OK = false;
+    if ( pxfile != NULL ) {
+        CheckSum = 0;
+        a = 0;
+        for ( a = 0; a < PX_LENGTH ; a++ ) {
+            r = fscanf(pxfile, "%i ", &v);
+            CheckSum += v;
+            PXNew[a] = (int8)v;
+        }
+        r = fscanf(pxfile, "%li ", &v);
+        CheckSum += (int32)v;
+        OK = CheckSum == 0;
+
+        fclose(pxfile);
+
+        if ( OK ) {
+            for ( a = 0; a < PX_LENGTH; a++ )
+                PX[a] = PXNew[a];
+            F.PXImageStale = false;
+        }
+    }
+
+    return( OK );
+
+} // ReadPXImagefile
+
+
+void CreateLogfile(void) {
+    static uint8 i;
+
+    UpdateRTC();
+    if ( F.SDCardValid )
+        strftime(RTCLogfile, 32, "/SDCard/L%H-%M.log", RTCTime );
+    else
+        strftime(RTCLogfile, 32, "/local/L%H-%M.log", RTCTime );
+
+    logfile = fopen(RTCLogfile, "w");
+
+    LogfileIsOpen = logfile != NULL;
+    if ( LogfileIsOpen ) {
+        i=0;
+        while ( RTCString[i] != 0 )
+            TxLogChar(RTCString[i++]);
+        TxLogChar(CR);
+        TxLogChar(LF);
+    }
+    LogChars = 0;
+
+} // CreateLogfile
+
+void CloseLogfile(void) {
+    fclose(logfile);
+} // CloseLog
+
+void TxLogChar(uint8 ch) {
+
+#ifndef SUPPRESS_SDCARD
+    if ( LogfileIsOpen )
+        fprintf(logfile, "%c",  ch);
+#endif // !SUPPRESS_SDCARD
+} // TxLogChar
+
+
+int8 ReadPX(uint16 a) {
+    static int8 b;
+    b = PX[a];
+    return(b);
+} // ReadPX
+
+int16 Read16PX(uint16 a) {
+    static i16u Temp16;
+
+    Temp16.b0 = ReadPX(a);
+    Temp16.b1 = ReadPX(a + 1);
+
+    return ( Temp16.i16 );
+} // Read16P
+
+int32 Read32PX(uint16 a) {
+    static i32u Temp32;
+
+    Temp32.b0 = ReadPX(a);
+    Temp32.b1 = ReadPX(a + 1);
+    Temp32.b2 = ReadPX(a + 2);
+    Temp32.b3 = ReadPX(a + 3);
+
+    return ( Temp32.i32 );
+} // Read32P
+
+void WritePX(uint16 a, int8 d) {
+    if ( PX[a] != d ) {
+        PX[a] = d;
+        F.PXImageStale = true;
+    }
+} // WritePX
+
+void Write16PX(uint16 a, int16 d) {
+    static i16u Temp16;
+
+    Temp16.i16 = d;
+    WritePX(a, Temp16.b0);
+    WritePX(a + 1, Temp16.b1);
+
+} // Write16P
+
+void Write32PX(uint16 a, int32 d) {
+    static i32u Temp32;
+
+    Temp32.i32 = d;
+    WritePX(a, Temp32.b0);
+    WritePX(a + 1, Temp32.b1);
+    WritePX(a + 2, Temp32.b2);
+    WritePX(a + 3, Temp32.b3);
+
+} // Write16PX
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/outputs.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,326 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+const real32 PWMScale = 1000.0 / OUT_MAXIMUM;
+
+void DoMulticopterMix(real32);
+void CheckDemand(real32);
+void MixAndLimitMotors(void);
+void MixAndLimitCam(void);
+void OutSignals(void);
+void InitI2CESCs(void);
+void StopMotors(void);
+void ExercisePWM(void);
+void InitMotors(void);
+
+boolean OutToggle;
+real32 PWM[8];
+real32 PWMSense[8];
+int16 ESCI2CFail[6];
+int16 CurrThrottle;
+int16 CamRollPulseWidth, CamPitchPulseWidth;
+int16 ESCMin, ESCMax;
+
+#define PWM_PERIOD_US         (1000000/PWM_UPDATE_HZ)
+
+#ifdef MULTICOPTER
+
+uint8 TC(int16 T) {
+    return ( Limit(T, ESCMin, ESCMax) );
+} // TC
+
+void DoMulticopterMix(real32 CurrThrottle) {
+    static real32 Temp;
+
+#ifdef Y6COPTER
+    PWM[FrontTC] = PWM[LeftTC] = PWM[RightTC] = CurrThrottle;
+#else
+    PWM[FrontC] = PWM[LeftC] = PWM[RightC] = PWM[BackC] = CurrThrottle;
+#endif
+
+#ifdef TRICOPTER // usually flown K1 motor to the rear - use orientation of 24
+    Temp = Pl * 0.5;
+    PWM[FrontC] -= Pl;            // front motor
+    PWM[LeftC] += (Temp - Rl);    // right rear
+    PWM[RightC] += (Temp + Rl);   // left rear
+
+    PWM[BackC] = -PWMSense[RudderC] * Yl + OUT_NEUTRAL;    // yaw servo
+    if ( fabs(K[Balance]) > 0.5 )
+        PWM[FrontC] =  PWM[FrontC] * K[Balance];
+#else
+#ifdef VTCOPTER     // usually flown VTail (K1+K4) to the rear - use orientation of 24
+    Temp = Pl * 0.5;
+
+    PWM[LeftC] += (Temp - Rl);    // right rear
+    PWM[RightC] += (Temp + Rl); // left rear
+
+    PWM[FrontLeftC] -= Pl - PWMSense[RudderC] * Yl;
+    PWM[FrontRightC] -= Pl + PWMSense[RudderC] * Yl;
+    if ( fabs(K[Balance]) > 0.01 ) {
+        PWM[FrontLeftC] = PWM[FrontLeftC] * K[Balance];
+        PWM[FrontRightC] = PWM[FrontRightC] * K[Balance];
+    }
+#else
+#ifdef Y6COPTER
+
+    Temp = Pl * 0.5;
+    PWM[FrontTC] -= Pl;             // front motor
+    PWM[LeftTC] += (Temp - Rl);     // right rear
+    PWM[RightTC] += (Temp + Rl); // left rear
+
+    PWM[FrontBC] = PWM[FrontTC];
+    PWM[LeftBC]  = PWM[LeftTC];
+    PWM[RightBC] = PWM[RightTC];
+
+    if ( fabs(K[Balance]) > 0.01 ) {
+        PWM[FrontTC] =  PWM[FrontTC] * K[Balance];
+        PWM[FrontBC] = PWM[FrontTC];
+    }
+
+    Temp = Yl * 0.5;
+    PWM[FrontTC] -= Temp;
+    PWM[LeftTC]  -= Temp;
+    PWM[RightTC] -= Temp;
+
+    PWM[FrontBC] += Temp;
+    PWM[LeftBC]  += Temp;
+    PWM[RightBC] += Temp;
+
+#else
+    PWM[LeftC]  += -Rl + Yl;
+    PWM[RightC] +=  Rl + Yl;
+    PWM[FrontC] += -Pl - Yl;
+    PWM[BackC]  +=  Pl - Yl;
+#endif
+#endif
+#endif
+
+} // DoMulticopterMix
+
+boolean     MotorDemandRescale;
+
+void CheckDemand(real32 CurrThrottle) {
+    static real32 Scale, ScaleHigh, ScaleLow, MaxMotor, DemandSwing;
+
+#ifdef Y6COPTER
+    MaxMotor = Max(PWM[FrontTC], PWM[LeftTC]);
+    MaxMotor = Max(MaxMotor, PWM[RightTC]);
+    MaxMotor = Max(MaxMotor, PWM[FrontBC]);
+    MaxMotor = Max(MaxMotor, PWM[LeftBC]);
+    MaxMotor = Max(MaxMotor, PWM[RightBC]);
+#else
+    MaxMotor = Max(PWM[FrontC], PWM[LeftC]);
+    MaxMotor = Max(MaxMotor, PWM[RightC]);
+#ifndef TRICOPTER
+    MaxMotor = Max(MaxMotor, PWM[BackC]);
+#endif // TRICOPTER
+#endif // Y6COPTER
+
+    DemandSwing = MaxMotor - CurrThrottle;
+
+    if ( DemandSwing > 0.0 ) {
+        ScaleHigh = (OUT_MAXIMUM - CurrThrottle) / DemandSwing;
+        ScaleLow = (CurrThrottle - IdleThrottle) / DemandSwing;
+        Scale = Min(ScaleHigh, ScaleLow); // just in case!
+        if ( Scale < 0.0 ) Scale = 1.0 / OUT_MAXIMUM;
+        if ( Scale < 1.0 ) {
+            MotorDemandRescale = true;
+            Rl *= Scale;  // could get rid of the divides
+            Pl *= Scale;
+#ifndef TRICOPTER
+            Yl *= Scale;
+#endif // TRICOPTER 
+        } else
+            MotorDemandRescale = false;
+    } else
+        MotorDemandRescale = false;
+
+} // CheckDemand
+
+#endif // MULTICOPTER
+
+void MixAndLimitMotors(void) {
+    static real32 Temp, TempElevon, TempElevator;
+    static uint8 m;
+
+    if ( DesiredThrottle < IdleThrottle )
+        CurrThrottle = 0;
+    else
+        CurrThrottle = DesiredThrottle;
+
+#ifdef MULTICOPTER
+    if ( State == InFlight )
+        CurrThrottle += (-Comp[UD] + Comp[Alt]); // vertical compensation not optional
+
+    Temp = OUT_MAXIMUM * 0.9; // 10% headroom for control
+    CurrThrottle = Limit(CurrThrottle, 0, Temp );
+
+    if ( CurrThrottle > IdleThrottle ) {
+        DoMulticopterMix(CurrThrottle);
+
+        CheckDemand(CurrThrottle);
+
+        if ( MotorDemandRescale )
+            DoMulticopterMix(CurrThrottle);
+    } else {
+#ifdef Y6COPTER
+        for ( m = 0; m < (uint8)6; m++ )
+            PWM[m] = CurrThrottle;
+#else
+        PWM[FrontC] = PWM[LeftC] = PWM[RightC] = CurrThrottle;
+#ifdef TRICOPTER
+        PWM[BackC] = -PWMSense[RudderC] * Yl + OUT_NEUTRAL;    // yaw servo
+#else
+        PWM[BackC] = CurrThrottle;
+#endif // !TRICOPTER
+#endif // Y6COPTER
+    }
+#else
+    CurrThrottle += Comp[Alt]; // simple - faster to climb with no elevator yet
+
+    PWM[ThrottleC] = CurrThrottle;
+    PWM[RudderC] = -PWMSense[RudderC] * Yl + OUT_NEUTRAL;
+
+#if ( defined AILERON | defined HELICOPTER )
+    PWM[AileronC] = PWMSense[AileronC] * Rl + OUT_NEUTRAL;
+    PWM[ElevatorC] = PWMSense[ElevatorC] * Pl + OUT_NEUTRAL;
+#else // ELEVON
+    TempElevator = PWMSense[2] * Pl + OUT_NEUTRAL;
+    PWM[RightElevonC] = PWMSense[RightElevonC] * (TempElevator + Rl);
+    PWM[LeftElevonC] = PWMSense[LeftElevonC] * (TempElevator -  Rl);
+#endif
+#endif
+
+} // MixAndLimitMotors
+
+void MixAndLimitCam(void) {
+    static real32 Temp; 
+
+    // use only roll/pitch angle estimates
+    Temp = Angle[Roll] * K[CamRollKp];
+    PWM[CamRollC] = Temp + K[CamRollTrim];
+    PWM[CamRollC] = PWM[CamRollC] + OUT_NEUTRAL; // PWMSense[CamRollC] * 
+
+    Temp = Angle[Pitch] * K[CamPitchKp];
+    PWM[CamPitchC] = Temp + DesiredCamPitchTrim;
+    PWM[CamPitchC] = PWM[CamPitchC] + OUT_NEUTRAL; //PWMSense[CamPitchC] * 
+    
+    CamRollPulseWidth = 1000 + (int16)( PWM[CamRollC] * PWMScale );
+    CamPitchPulseWidth = 1000 + (int16)( PWM[CamPitchC] * PWMScale );
+
+} // MixAndLimitCam
+
+#if ( defined Y6COPTER )
+#include "outputs_y6.h"
+#else
+#if ( defined TRICOPTER | defined MULTICOPTER | defined VTCOPTER )
+#include "outputs_copter.h"
+#else
+#include "outputs_conventional.h"
+#endif // Y6COPTER
+#endif // TRICOPTER | MULTICOPTER
+
+void InitI2CESCs(void) {
+    static int8 m;
+    static uint8 r;
+
+#ifdef MULTICOPTER
+
+    if ( P[ESCType] ==  ESCHolger )
+        for ( m = 0 ; m < NoOfI2CESCOutputs ; m++ ) {
+            I2CESC.start();
+            r = I2CESC.write(0x52 + ( m*2 ));        // one cmd, one data byte per motor
+            r += I2CESC.write(0);
+            ESCI2CFail[m] += r;
+            I2CESC.stop();
+        }
+    else
+        if ( P[ESCType] == ESCYGEI2C )
+            for ( m = 0 ; m < NoOfI2CESCOutputs ; m++ ) {
+                I2CESC.start();
+                r = I2CESC.write(0x62 + ( m*2 ));    // one cmd, one data byte per motor
+                r += I2CESC.write(0);
+                ESCI2CFail[m] += r;
+                I2CESC.stop();
+            }
+        else
+            if ( P[ESCType] == ESCX3D ) {
+                I2CESC.start();
+                r = I2CESC.write(0x10);            // one command, 4 data bytes
+                r += I2CESC.write(0);
+                r += I2CESC.write(0);
+                r += I2CESC.write(0);
+                r += I2CESC.write(0);
+                ESCI2CFail[0] += r;
+                I2CESC.stop();
+            }
+#endif // MULTICOPTER
+} // InitI2CESCs
+
+void StopMotors(void) {
+#ifdef MULTICOPTER
+#ifdef Y6COPTER
+    PWM[FrontTC] = PWM[LeftTC] = PWM[RightTC] =
+    PWM[FrontBC] = PWM[LeftBC] = PWM[RightBC] = ESCMin;
+#else
+    PWM[FrontC] = PWM[LeftC] = PWM[RightC] = ESCMin;
+#ifndef TRICOPTER
+    PWM[BackC] = ESCMin;
+#endif // !TRICOPTER
+#endif // Y6COPTER    
+#else
+    PWM[ThrottleC] = ESCMin;
+#endif // MULTICOPTER
+
+    Out0.pulsewidth_us(1000 + (int16)( PWM[FrontC] * PWMScale ) );
+    Out1.pulsewidth_us(1000 + (int16)( PWM[LeftC] * PWMScale ) );
+    Out2.pulsewidth_us(1000 + (int16)( PWM[RightC] * PWMScale ) );
+    Out3.pulsewidth_us(1000 + (int16)( PWM[BackC] * PWMScale ) );
+
+    CamRollPulseWidth = 1000 + (int16)( PWM[CamRollC] * PWMScale );
+    CamPitchPulseWidth = 1000 + (int16)( PWM[CamPitchC] * PWMScale );
+    
+#ifndef SOFTWARE_CAM_PWM 
+    Out4.pulsewidth_us(CamRollPulseWidth);
+    Out5.pulsewidth_us(CamPitchPulseWidth);
+#endif // !SOFTWARE_CAM_PWM
+
+    F.MotorsArmed = false;
+} // StopMotors
+
+void InitMotors(void) {
+    static uint8 m;
+
+    Out0.period_us(PWM_PERIOD_US);
+
+    StopMotors();
+
+#ifndef Y6COPTER
+#ifdef TRICOPTER
+    PWM[BackC] = OUT_NEUTRAL;
+#endif // !TRICOPTER    
+    PWM[CamRollC] = OUT_NEUTRAL;
+    PWM[CamPitchC] = OUT_NEUTRAL;
+#endif // Y6COPTER
+
+} // InitMotors
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/outputs_conventional.h	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,54 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+
+void OutSignals(void) {
+    static int8 m;
+    static uint8 r;
+
+    for ( m = 0; m < (uint8)6; m++ )
+        PWM[m] = Limit(PWM[m], ESCMin, ESCMax);
+
+#if !( defined SIMULATE | defined TESTING )
+
+    if ( !F.MotorsArmed )
+        StopMotors();
+
+#ifdef ELEVON
+    Out0.pulsewidth_us(1000 + (int16)( PWM[ThrottleC] * PWMScale ) );
+    Out1.pulsewidth_us(1000 + (int16)( PWM[RightElevonC] * PWMScale ) );
+    Out2.pulsewidth_us(1000 + (int16)( PWM[LeftElevonC] * PWMScale ) );
+    Out3.pulsewidth_us(1000 + (int16)( PWM[RudderC] * PWMScale ) );
+#else
+    Out0.pulsewidth_us(1000 + (int16)( PWM[ThrottleC] * PWMScale ) );
+    Out1.pulsewidth_us(1000 + (int16)( PWM[AileronC] * PWMScale ) );
+    Out2.pulsewidth_us(1000 + (int16)( PWM[ElevatorC] * PWMScale ) );
+    Out3.pulsewidth_us(1000 + (int16)( PWM[RudderC] * PWMScale ) );
+#endif
+
+} // OutSignals
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/outputs_copter.h	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,99 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+
+void OutSignals(void) {
+    static int8 m;
+    static uint8 r;
+
+#if !( defined SIMULATE | defined TESTING )
+
+    if ( !F.MotorsArmed )
+        StopMotors();
+
+    PWM[FrontC] = TC(PWM[FrontC]);
+    PWM[LeftC] = TC(PWM[LeftC]);
+    PWM[RightC] = TC(PWM[RightC]);
+#ifdef TRICOPTER
+    PWM[BackC] = Limit(PWM[BackC], 1, OUT_MAXIMUM);
+#else
+    PWM[BackC] = TC(PWM[BackC]);
+#endif
+
+    Out0.pulsewidth_us(1000 + (int16)( PWM[FrontC] * PWMScale ) );
+    Out1.pulsewidth_us(1000 + (int16)( PWM[LeftC] * PWMScale ) );
+    Out2.pulsewidth_us(1000 + (int16)( PWM[RightC] * PWMScale ) );
+    Out3.pulsewidth_us(1000 + (int16)( PWM[BackC] * PWMScale ) );
+                      
+#ifdef MULTICOPTER
+    // in X3D and Holger-Mode, K2 (left motor) is SDA, K3 (right) is SCL.
+    // ACK (r) not checked as no recovery is possible.
+    // Octocopters may have ESCs paired with common address so ACK is meaningless.
+    // All motors driven with fourth motor ignored for Tricopter.
+
+    if ( P[ESCType] ==  ESCHolger )
+        for ( m = 0 ; m < NoOfI2CESCOutputs ; m++ ) {
+            I2CESC.start();
+            r = I2CESC.write(0x52 + ( m*2 ));        // one command, one data byte per motor
+            r += I2CESC.write( PWM[m] );
+            ESCI2CFail[m] += r;
+            I2CESC.stop();
+        }
+    else
+        if ( P[ESCType] == ESCYGEI2C )
+            for ( m = 0 ; m < NoOfI2CESCOutputs ; m++ ) {
+                I2CESC.start();
+                r = I2CESC.write(0x62 + ( m*2) );    // one cmd, one data byte per motor
+                r += I2CESC.write( PWM[m] * 0.5 );
+                ESCI2CFail[m] += r;
+                I2CESC.stop();
+            }
+        else
+            if ( P[ESCType] == ESCX3D ) {
+                I2CESC.start();
+                r = I2CESC.write(0x10);                // one command, 4 data bytes
+                r += I2CESC.write( PWM[FrontC] );
+                r += I2CESC.write( PWM[BackC] );
+                r += I2CESC.write( PWM[LeftC] );
+                r += I2CESC.write( PWM[RightC] );
+                ESCI2CFail[0] += r;
+                //  other ESCs if a Hexacopter
+                I2CESC.stop();
+            }
+#endif //  MULTICOPTER
+
+#else
+
+    PWM[FrontC] = Limit(PWM[FrontC], ESCMin, ESCMax);
+    PWM[LeftC] = Limit(PWM[LeftC], ESCMin, ESCMax);
+    PWM[RightC] = Limit(PWM[RightC], ESCMin, ESCMax);
+#ifdef TRICOPTER
+    PWM[BackC] = Limit(PWM[BackC], 1, OUT_MAXIMUM);
+#else
+    PWM[BackC] = Limit(PWM[BackC], ESCMin, ESCMax);
+#endif
+
+#endif // !(SIMULATE | TESTING)
+
+} // OutSignals
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/outputs_y6.h	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,60 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+
+void OutSignals(void) {   // The PWM pulses are in two parts these being a 1mS preamble followed by a 0-1mS part.
+    // Interrupts are enabled during the first part which uses TMR0.  TMR0 is monitored until
+    // there is just sufficient time for one remaining interrupt latency before disabling
+    // interrupts.  We do this because there appears to be no atomic method of detecting the
+    // remaining time AND conditionally disabling the interupt.
+    static int8 m;
+    static uint8 r, s;
+    static i16u SaveTimer0;
+    static uint24 SaveClockmS;
+
+    PWM[FrontTC] = TC(PWM[FrontTC]);
+    PWM[LeftTC] = TC(PWM[LeftTC]);
+    PWM[RightTC] = TC(PWM[RightTC]);
+    PWM[FrontBC] = TC(PWM[FrontBC]);
+    PWM[LeftBC] = TC(PWM[LeftBC]);
+    PWM[RightBC] = TC(PWM[RightBC]);
+
+#if !( defined SIMULATE | defined TESTING )
+
+    if ( !F.MotorsArmed )
+        StopMotors();
+    
+    Out0.pulsewidth_us(1000 + (int16)( PWM[FrontTC] * PWMScale ) );
+    Out1.pulsewidth_us(1000 + (int16)( PWM[LeftTC] * PWMScale ) );
+    Out2.pulsewidth_us(1000 + (int16)( PWM[RightTC] * PWMScale ) );
+    Out3.pulsewidth_us(1000 + (int16)( PWM[FrontBC] * PWMScale ) );
+    
+    #ifdef USING_PWM4AND5
+    Out4.pulsewidth_us(1000 + (int16)( PWM[LeftBC] * PWMScale ) );
+    Out5.pulsewidth_us(1000 + (int16)( PWM[RightBC] * PWMScale ) );
+    #endif // USING_PWM4AND5
+    
+#endif // !(SIMULATE | TESTING)
+
+} // OutSignals
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/params.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,335 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+void ReadParameters(void);
+void UseDefaultParameters(void);
+void UpdateWhichParamSet(void);
+boolean ParameterSanityCheck(void);
+void InitParameters(void);
+
+const uint8 ESCLimits [] = { OUT_MAXIMUM, OUT_HOLGER_MAXIMUM, OUT_X3D_MAXIMUM, OUT_YGEI2C_MAXIMUM };
+
+#ifdef MULTICOPTER
+#include "uavx_multicopter.h"
+#else
+#ifdef HELICOPTER
+#include "uavx_helicopter.h"
+#else
+#ifdef ELEVONS
+#include "uavx_elevon.h"
+#else
+#include "uavx_aileron.h"
+#endif
+#endif
+#endif
+
+uint8 ParamSet;
+boolean ParametersChanged, SaveAllowTurnToWP;
+
+int8 P[MAX_PARAMETERS];
+real32 K[MAX_PARAMETERS]; // Arm rescaled legacy parameters as appropriate
+
+real32 OSin[48], OCos[48];
+
+uint8 Orientation , PolarOrientation;
+uint8 UAVXAirframe;
+
+void Legacy(void) {
+    static uint8 p;
+
+    for ( p = 0; p <MAX_PARAMETERS; p++ ) // brute force
+        K[p] = (float)P[p];
+
+    // Rate Control
+    K[RollKp] *= 2.6;
+    K[RollKi] *= 20.7;
+    K[RollKd]  = -K[RollKd] * 0.021;
+    K[RollIntLimit] *= DEGRAD;
+
+    K[PitchKp] *= 2.6;
+    K[PitchKi] *= 20.7;
+    K[PitchKd]  = -K[PitchKd] * 0.021;
+    K[PitchIntLimit] *= DEGRAD;
+
+    K[YawKp] *= 2.6;
+    K[YawKi] *= 41.4;
+    K[YawKd]  = -K[YawKd] * 0.0004;
+
+    // Angle Control
+
+    // not yet
+
+    // Inertial Damping
+    K[VertDampKp] *= 0.1; // one click/MPS
+    K[HorizDampKp] *= 0.1;
+    K[VertDampDecay] *= 0.01;
+    K[HorizDampDecay] *= 0.01;
+
+    // Altitude Hold
+    K[AltKp] *= 0.625;
+    K[AltKi] *= 25.0;
+    K[AltKd] *= 0.125;
+
+    // Navigation
+    K[NavKi] *= 0.08;
+    K[NavKd] *= 0.0008;
+    
+    K[Balance] = ( 128.0 + (float)P[Balance])/128.0;
+    
+    K[CompassKp] = P[CompassKp] / 4096.0;
+    K[YawIntLimit] = P[YawIntLimit] * 256.0 /1000.0;
+
+    // Camera
+    K[CamRollKp] *= 5.0;
+    K[CamPitchKp] *= 5.0;
+
+    // Acceleration Neutrals
+    K[MiddleBF] = P[MiddleBF] * 0.001; // mG
+    K[MiddleLR] = P[MiddleLR] * 0.001;
+    K[MiddleUD] = P[MiddleUD] * 0.001;
+
+    K[LowVoltThres] *= 0.2;
+
+} // Legacy
+
+void ReadParameters(void) {
+    static int8 i, b, a;
+
+    if ( ParametersChanged ) {  // overkill if only a single parameter has changed but is not in flight loop
+        a = (ParamSet - 1)* MAX_PARAMETERS;
+        for ( i = 0; i < MAX_PARAMETERS; i++)
+            P[i] = ReadPX(a + i);
+
+        Legacy();
+
+        ESCMax = ESCLimits[P[ESCType]];
+        if ( P[ESCType] == ESCPPM )
+            ESCMin = 1;
+        else {
+            ESCMin = 0;
+            for ( i = 0; i < NoOfI2CESCOutputs; i++ )
+                ESCI2CFail[i] = 0;
+            InitI2CESCs();
+        }
+
+        b = P[ServoSense];
+        for ( i = 0; i < 8; i++ ) {
+            if ( b & 1 )
+                PWMSense[i] = -1;
+            else
+                PWMSense[i] = 1;
+            b >>=1;
+        }
+
+        F.UsingPositionHoldLock = ( (P[ConfigBits] & UsePositionHoldLockMask ) != 0);
+        F.UsingPolarCoordinates = ( (P[ConfigBits] & UsePolarMask ) != 0);
+
+        for ( i = 0; i < CONTROLS; i++) // make reverse map
+            RMap[Map[P[TxRxType]][i]] = i;
+
+        IdleThrottle = Limit((int16)P[PercentIdleThr], 10, 30); // 10-30%
+        IdleThrottle = (IdleThrottle * OUT_MAXIMUM )/100L;
+        CruiseThrottle = ((int16)P[PercentCruiseThr] * OUT_MAXIMUM )/100L;
+        MaxCruiseThrottle = (RC_MAXIMUM * 60L * OUT_MAXIMUM)/100L; // 60%
+
+        NavNeutralRadius = Limit((int16)P[NeutralRadius], 0, NAV_MAX_NEUTRAL_RADIUS);
+        NavNeutralRadius = ConvertMToGPS(NavNeutralRadius);
+
+        NavYCorrLimit = Limit((int16)P[NavYawLimit], 5, 50);
+
+        MagDeviation = (real32)P[NavMagVar] * DEGRAD;
+        CompassOffset = ((real32)((int16)P[CompassOffsetQtr] * 90L) * DEGRAD );
+        InitCompass();
+
+#ifdef MULTICOPTER
+        Orientation = P[Orient];
+        if (Orientation == 0xff ) // uninitialised
+            Orientation = 0;
+#else
+        Orientation = 0;
+#endif // MULTICOPTER
+
+        F.UsingSerialPPM = ( P[TxRxType] == FrSkyDJT_D8R ) || ( P[TxRxType] == ExternalDecoder ) || ( (P[ConfigBits] & RxSerialPPMMask ) != 0);
+        DoRxPolarity();
+        PPM_Index = PrevEdge = 0;
+
+        F.UsingPolar = ((P[ConfigBits] & UsePolarMask) != 0);
+        F.RFInInches = ((P[ConfigBits] & RFInchesMask) != 0);
+
+        F.UsingTxMode2 = ((P[ConfigBits] & TxMode2Mask) != 0);
+
+        if ( P[GyroRollPitchType] == IRSensors )
+            F.UsingAngleControl = true;
+        else
+            F.UsingAngleControl = ((P[ConfigBits] & UseAngleControlMask) != 0);
+
+        F.UsingRTHAutoDescend = ((P[ConfigBits] & UseRTHDescendMask) != 0);
+        NavRTHTimeoutmS = (uint24)P[DescentDelayS]*1000L;
+
+        BatteryVolts = K[LowVoltThres];
+        BatteryCurrent = 0;
+
+        F.ParametersValid = ParameterSanityCheck();
+
+        ParametersChanged = false;
+
+    }
+} // ReadParameters
+
+void UseDefaultParameters(void) { // loads a representative set of initial parameters as a base for tuning
+    int8 p, d;
+    static int16 a;
+
+    for ( a = 0; a < PX_LENGTH; a++ )
+        PX[a] = 0xff;
+
+    for ( p = 0; p < MAX_PARAMETERS; p++ ) {
+        d = DefaultParams[p][0];
+        WritePX(p, d);
+        WritePX(p+MAX_PARAMETERS, d);
+    }
+
+    WritePX(NAV_NO_WP, 0); // set NoOfWaypoints to zero
+
+    WritePXImagefile();
+
+    TxString("\r\nDefault Parameters Loaded\r\n");
+    TxString("Do a READ CONFIG to refresh the UAVPSet parameter display\r\n");
+} // UseDefaultParameters
+
+void UpdateParamSetChoice(void) {
+#define STICK_WINDOW 30
+
+    uint8 NewParamSet, NewAllowNavAltitudeHold, NewAllowTurnToWP;
+    int8 Selector;
+
+    NewParamSet = ParamSet;
+    NewAllowNavAltitudeHold = F.AllowNavAltitudeHold;
+    NewAllowTurnToWP = F.AllowTurnToWP;
+
+    if ( F.UsingTxMode2 )
+        Selector = DesiredRoll;
+    else
+        Selector = -DesiredYaw;
+
+    if ( (abs(DesiredPitch) > STICK_WINDOW) && (abs(Selector) > STICK_WINDOW) ) {
+        if ( DesiredPitch > STICK_WINDOW ) { // bottom
+            if ( Selector < -STICK_WINDOW ) // left
+            { // bottom left
+                NewParamSet = 1;
+                NewAllowNavAltitudeHold = true;
+            } else
+                if ( Selector > STICK_WINDOW ) // right
+                { // bottom right
+                    NewParamSet = 2;
+                    NewAllowNavAltitudeHold = true;
+                }
+        } else
+            if ( DesiredPitch < -STICK_WINDOW ) { // top
+                if ( Selector < -STICK_WINDOW ) { // left
+                    NewAllowNavAltitudeHold = false;
+                    NewParamSet = 1;
+                } else
+                    if ( Selector > STICK_WINDOW ) { // right
+                        NewAllowNavAltitudeHold = false;
+                        NewParamSet = 2;
+                    }
+            }
+
+        if ( ( NewParamSet != ParamSet ) || ( NewAllowNavAltitudeHold != F.AllowNavAltitudeHold ) ) {
+            ParamSet = NewParamSet;
+            F.AllowNavAltitudeHold = NewAllowNavAltitudeHold;
+            LEDBlue_ON;
+            DoBeep100mS(2, 2);
+            if ( ParamSet == (uint8)2 )
+                DoBeep100mS(2, 2);
+            if ( F.AllowNavAltitudeHold )
+                DoBeep100mS(4, 4);
+            ParametersChanged |= true;
+            Beeper_OFF;
+            LEDBlue_OFF;
+        }
+    }
+
+    if ( F.UsingTxMode2 )
+        Selector = -DesiredYaw;
+    else
+        Selector = DesiredRoll;
+
+    if ( (abs(RC[ThrottleC]) < STICK_WINDOW) && (abs(Selector) > STICK_WINDOW ) ) {
+        if ( Selector < -STICK_WINDOW ) // left
+            NewAllowTurnToWP = false;
+        else
+            if ( Selector > STICK_WINDOW ) // left
+                NewAllowTurnToWP = true; // right
+
+        if ( NewAllowTurnToWP != F.AllowTurnToWP ) {
+            F.AllowTurnToWP = NewAllowTurnToWP;
+            LEDBlue_ON;
+            //    if ( F.AllowTurnToWP )
+            DoBeep100mS(4, 2);
+
+            LEDBlue_OFF;
+        }
+    }
+
+    SaveAllowTurnToWP = F.AllowTurnToWP;
+
+} // UpdateParamSetChoice
+
+boolean ParameterSanityCheck(void) {
+    static boolean Fail;
+
+    Fail = (P[RollKp] == 0) ||
+           (P[PitchKp] == 0) ||
+           (P[YawKp] == 0);
+
+    return ( !Fail );
+} // ParameterSanityCheck
+
+void InitParameters(void) {
+    static int8 i;
+    static real32 A;
+
+    F.ParametersValid = false;
+    if ( !ReadPXImagefile() )
+        UseDefaultParameters();
+
+    UAVXAirframe = AF_TYPE;
+
+    for (i = 0; i < 48; i++) {
+        A = ((real32)i * PI)/24.0;
+        OSin[i] = sin(A);
+        OCos[i] = cos(A);
+    }
+    Orientation = 0;
+
+    ALL_LEDS_ON;
+
+    ParametersChanged = true;
+    ParamSet = 1;
+    ReadParameters();
+
+    ALL_LEDS_OFF;
+} // InitParameters
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rc.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,391 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+void DoRxPolarity(void);
+void InitRC(void);
+void MapRC(void);
+void CheckSticksHaveChanged(void);
+void UpdateControls(void);
+void CaptureTrims(void);
+void CheckThrottleMoved(void);
+void ReceiverTest(void);
+
+const uint8 Map[CustomTxRx+1][CONTROLS] = {
+    { 2,0,1,3,4,5,6 },     // Futaba Thr 3 Throttle
+    { 1,0,3,2,4,5,6 },    // Futaba Thr 2 Throttle
+    { 4,2,1,0,5,3,6 },    // Futaba 9C Spektrum DM8/AR7000
+    { 0,1,2,3,4,5,6 },    // JR XP8103/PPM
+    { 6,0,3,5,2,4,1 },    // JR 9XII Spektrum DM9 ?
+
+    { 5,0,3,6,2,1,4 },    // JR DXS12 
+    { 5,0,3,6,2,1,4 },    // Spektrum DX7/AR7000
+    { 4,0,3,5,2,1,6 },    // Spektrum DX7/AR6200
+
+    { 2,0,1,3,4,6,5 },     // Futaba Thr 3 Sw 6/7
+    { 0,1,2,3,4,5,6 },    // Spektrum DX7/AR6000
+    { 0,1,2,3,4,5,6 },    // Graupner MX16S
+    { 4,0,2,3,1,5,6 },    // Spektrum DX6i/AR6200
+    { 2,0,1,3,4,5,6 },    // Futaba Th 3/R617FS
+    { 4,0,2,3,5,1,6 },    // Spektrum DX7a/AR7000
+    { 2,0,1,3,4,6,5 },     // External decoder (Futaba Thr 3 6/7 swap)
+    { 0,1,2,3,4,5,6 },    // FrSky DJT/D8R-SP
+    { 5,0,3,6,2,1,4 },    // UNDEFINED Spektrum DX7/AR7000
+    { 2,0,1,3,4,5,6 }    // Custom
+//{ 4,0,2,1,3,5,6 }    // Custom
+    };
+
+// Rx signalling polarity used only for serial PPM frames usually
+// by tapping internal Rx circuitry.
+const boolean PPMPosPolarity[CustomTxRx+1] =
+    {
+        false,     // Futaba Ch3 Throttle
+        false,    // Futaba Ch2 Throttle
+        true,    // Futaba 9C Spektrum DM8/AR7000
+        true,    // JR XP8103/PPM
+        true,    // JR 9XII Spektrum DM9/AR7000
+
+        true,    // JR DXS12
+        true,    // Spektrum DX7/AR7000
+        true,    // Spektrum DX7/AR6200
+        false,    // Futaba Thr 3 Sw 6/7
+        true,    // Spektrum DX7/AR6000
+        true,    // Graupner MX16S
+        true,    // Graupner DX6i/AR6200
+        true,    // Futaba Thr 3/R617FS
+        true,     // Spektrum DX7a/AR7000
+        false,     // External decoder (Futaba Ch3 Throttle)
+        true,    // FrSky DJT/D8R-SP
+        true,    // UNKNOWN using Spektrum DX7/AR7000
+        true    // custom Tx/Rx combination
+    };
+
+// Reference Internal Quadrocopter Channel Order
+// 0 Throttle
+// 1 Aileron
+// 2 Elevator
+// 3 Rudder
+// 4 Gear
+// 5 Aux1
+// 6 Aux2
+
+int8 RMap[CONTROLS];
+
+int16x8x4Q PPMQ;
+int16 PPMQSum[CONTROLS];
+int16 RC[CONTROLS], RCp[CONTROLS];
+int16 Trim[3];
+int16 ThrLow, ThrNeutral, ThrHigh;
+
+boolean RCPositiveEdge;
+
+void DoRxPolarity(void) {
+
+    RCInterrupt.rise(&RCNullISR);
+    RCInterrupt.fall(&RCNullISR);
+
+    if ( F.UsingSerialPPM  ) // serial PPM frame from within an Rx
+        if  ( PPMPosPolarity[P[TxRxType]] )
+            RCInterrupt.rise(&RCISR);
+        else
+            RCInterrupt.fall(&RCISR);
+    else {
+        RCInterrupt.rise(&RCISR);
+        RCInterrupt.fall(&RCISR);
+    }
+
+}  // DoRxPolarity
+
+void InitRC(void) {
+    static int8 c, i, q;
+
+    DoRxPolarity();
+
+    SignalCount = -RC_GOOD_BUCKET_MAX;
+    F.Signal = F.RCNewValues = false;
+
+    for (c = 0; c < RC_CONTROLS; c++) {
+        PPM[c] = 0;
+        RC[c] = RCp[c] = RC_NEUTRAL;
+
+        for (q = 0; q <= PPMQMASK; q++)
+            PPMQ.B[q][c] = RC_NEUTRAL;
+        PPMQSum[c] = RC_NEUTRAL * 4;
+    }
+    PPMQ.Head = 0;
+
+    DesiredRoll = DesiredPitch = DesiredYaw = DesiredThrottle = StickThrottle = 0;
+
+    for ( i = 0; i < 3; i++ )
+        Trim[i] = 0;
+
+    PPM_Index = PrevEdge = RCGlitches = 0;
+} // InitRC
+
+void MapRC(void) { // re-maps captured PPM to Rx channel sequence
+    static int8 c;
+    static int16 LastThrottle, i;
+    static uint16 Sum;
+
+    LastThrottle = RC[ThrottleC];
+
+    for ( c = 0 ; c < RC_CONTROLS ; c++ ) {
+        Sum = PPM[c];
+        PPMQSum[c] -= PPMQ.B[PPMQ.Head][c];
+        PPMQ.B[PPMQ.Head][c] = Sum;
+        PPMQSum[c] += Sum;
+        PPMQ.Head = (PPMQ.Head + 1) & PPMQMASK;
+    }
+
+    for ( c = 0 ; c < RC_CONTROLS ; c++ ) {
+        i = Map[P[TxRxType]][c];
+        RC[c] = ( PPMQSum[i] * RC_MAXIMUM ) / 4000; // needs rethink - throwing away precision
+    }
+
+    if ( THROTTLE_SLEW_LIMIT > 0 )
+        RC[ThrottleRC] = SlewLimit(LastThrottle, RC[ThrottleRC], THROTTLE_SLEW_LIMIT);
+
+} // MapRC
+
+void CheckSticksHaveChanged(void) {
+    static boolean Change;
+    static uint8 c;
+
+    if ( F.ReturnHome || F.Navigate  ) {
+        if ( mSClock() > mS[StickChangeUpdate] ) {
+            mS[StickChangeUpdate] = mSClock() + 500;
+            if ( !F.ForceFailsafe && ( State == InFlight )) {
+                Stats[RCFailsafesS]++;
+                mS[NavStateTimeout] = mSClock() + NAV_RTH_LAND_TIMEOUT_MS;
+                mS[DescentUpdate]  = mSClock() + ALT_DESCENT_UPDATE_MS;
+                DescentComp = 0; // for no Baro case
+            }
+
+            F.ForceFailsafe = State == InFlight; // abort if not navigating
+        }
+    } else {
+        if ( mSClock() > mS[StickChangeUpdate] ) {
+            mS[StickChangeUpdate] = mSClock() + 500;
+
+            Change = false;
+            for ( c = ThrottleC; c <= (uint8)RTHC; c++ ) {
+                Change |= abs( RC[c] - RCp[c]) > RC_STICK_MOVEMENT;
+                RCp[c] = RC[c];
+            }
+        }
+
+        if ( Change ) {
+            mS[RxFailsafeTimeout] = mSClock() + RC_NO_CHANGE_TIMEOUT_MS;
+            mS[NavStateTimeout] = mSClock();
+            F.ForceFailsafe = false;
+            if ( FailState == MonitoringRx ) {
+                if ( F.LostModel ) {
+                    Beeper_OFF;
+                    F.LostModel = false;
+                    DescentComp = 0;
+                }
+            }
+        } else
+            if ( mSClock() > mS[RxFailsafeTimeout] ) {
+                if ( !F.ForceFailsafe && ( ( State == InFlight ) || ( ( mSClock() - mS[RxFailsafeTimeout])  > 120000 ) ) ) {
+                    Stats[RCFailsafesS]++;
+                    mS[NavStateTimeout] = mSClock() + NAV_RTH_LAND_TIMEOUT_MS;
+                    mS[DescentUpdate]  = mSClock() + ALT_DESCENT_UPDATE_MS;
+                    DescentComp = 0; // for no Baro case
+                    F.ForceFailsafe = true;
+                }
+
+                //    F.ForceFailsafe = State == InFlight; // abort if not navigating
+            }
+    }
+
+} // CheckSticksHaveChanged
+
+void UpdateControls(void) {
+    static int16 HoldRoll, HoldPitch, RollPitchScale;
+    static boolean NewCh5Active;
+
+    F.RCNewValues = false;
+
+    MapRC();                                // remap channel order for specific Tx/Rx
+
+    StickThrottle = RC[ThrottleRC];
+
+    //_________________________________________________________________________________________
+
+    // Navigation
+
+    F.ReturnHome = F.Navigate = F.UsingPolar = false;
+    NewCh5Active = RC[RTHRC] > RC_NEUTRAL;
+
+    if ( F.UsingPositionHoldLock )
+        if ( NewCh5Active & !F.Ch5Active )
+            F.AllowTurnToWP = true;
+        else
+            F.AllowTurnToWP = SaveAllowTurnToWP;
+    else
+        if ( RC[RTHRC] > ((3L*RC_MAXIMUM)/4) )
+            F.ReturnHome = true;
+        else
+            if ( RC[RTHRC] > (RC_NEUTRAL/2) )
+                F.Navigate = true;
+
+    F.Ch5Active = NewCh5Active;
+
+#ifdef RX6CH
+    DesiredCamPitchTrim = RC_NEUTRAL;
+    // NavSensitivity set in ReadParametersPX
+#else
+    DesiredCamPitchTrim = RC[CamPitchRC] - RC_NEUTRAL;
+    NavSensitivity = RC[NavGainRC];
+    NavSensitivity = Limit(NavSensitivity, 0, RC_MAXIMUM);
+#endif // !RX6CH
+
+    //_________________________________________________________________________________________
+
+    // Altitude Hold
+
+    F.AltHoldEnabled = NavSensitivity > NAV_SENS_ALTHOLD_THRESHOLD;
+
+    if ( NavState == HoldingStation ) { // Manual
+        if ( StickThrottle < RC_THRES_STOP )    // to deal with usual non-zero EPA
+            StickThrottle = 0;
+    } else // Autonomous
+        if ( F.AllowNavAltitudeHold &&  F.AltHoldEnabled )
+            StickThrottle = CruiseThrottle;
+
+    if ( (! F.HoldingAlt) && (!(F.Navigate || F.ReturnHome )) ) // cancel any current altitude hold setting
+        DesiredAltitude = Altitude;
+
+    //_________________________________________________________________________________________
+
+    // Attitude
+
+#ifdef ATTITUDE_NO_LIMITS
+    DesiredRoll = RC[RollRC] - RC_NEUTRAL;
+    DesiredPitch = RC[PitchRC] - RC_NEUTRAL;
+#else
+    RollPitchScale = MAX_ROLL_PITCH - (NavSensitivity >> 2);
+    DesiredRoll = SRS16((RC[RollRC] - RC_NEUTRAL) * RollPitchScale, 7);
+    DesiredPitch = SRS16((RC[PitchRC] - RC_NEUTRAL) * RollPitchScale, 7);
+#endif // ATTITUDE_NO_LIMITS
+    DesiredYaw = RC[YawRC] - RC_NEUTRAL;
+
+    HoldRoll = DesiredRoll - Trim[Roll];
+    HoldRoll = abs(HoldRoll);
+    HoldPitch = DesiredPitch - Trim[Pitch];
+    HoldPitch = abs(HoldPitch);
+    CurrMaxRollPitch = Max(HoldRoll, HoldPitch);
+
+    if ( CurrMaxRollPitch > ATTITUDE_HOLD_LIMIT )
+        if ( AttitudeHoldResetCount > ATTITUDE_HOLD_RESET_INTERVAL )
+            F.AttitudeHold = false;
+        else {
+            AttitudeHoldResetCount++;
+            F.AttitudeHold = true;
+        }
+    else {
+        F.AttitudeHold = true;
+        if ( AttitudeHoldResetCount > 1 )
+            AttitudeHoldResetCount -= 2;        // Faster decay
+    }
+
+    //_________________________________________________________________________________________
+
+    // Rx has gone to failsafe
+
+    //zzz  CheckSticksHaveChanged();
+
+    F.NewCommands = true;
+
+} // UpdateControls
+
+void CaptureTrims(void) {    // only used in detecting movement from neutral in hold GPS position
+    // Trims are invalidated if Nav sensitivity is changed - Answer do not use trims ?
+    Trim[Roll] = Limit(DesiredRoll, -NAV_MAX_TRIM, NAV_MAX_TRIM);
+    Trim[Pitch] = Limit(DesiredPitch, -NAV_MAX_TRIM, NAV_MAX_TRIM);
+    Trim[Yaw] = Limit(DesiredYaw, -NAV_MAX_TRIM, NAV_MAX_TRIM);
+
+    HoldYaw = 0;
+} // CaptureTrims
+
+void CheckThrottleMoved(void) {
+    if ( mSClock() < mS[ThrottleUpdate] )
+        ThrNeutral = DesiredThrottle;
+    else {
+        ThrLow = ThrNeutral - THROTTLE_MIDDLE;
+        ThrLow = Max(ThrLow, THROTTLE_MIN_ALT_HOLD);
+        ThrHigh = ThrNeutral + THROTTLE_MIDDLE;
+        if ( ( DesiredThrottle <= ThrLow ) || ( DesiredThrottle >= ThrHigh ) ) {
+            mS[ThrottleUpdate] = mSClock() + THROTTLE_UPDATE_MS;
+            F.ThrottleMoving = true;
+        } else
+            F.ThrottleMoving = false;
+    }
+} // CheckThrottleMoved
+
+void ReceiverTest(void) {
+    static int8 s;
+
+    TxString("\r\nRx Test \r\n");
+
+    TxString("\r\nRx: ");
+    ShowRxSetup();
+    TxString("\r\n");
+
+    TxString("RAW Rx frame values - neutrals NOT applied\r\n");
+    TxString("Channel order is: ");
+    for ( s = 0; s < RC_CONTROLS; s++)
+        TxChar(RxChMnem[RMap[s]]);
+
+    if ( F.Signal )
+        TxString("\r\nSignal OK ");
+    else
+        TxString("\r\nSignal FAIL ");
+    TxVal32(mSClock() - mS[LastValidRx], 0, 0);
+    TxString(" mS ago\r\n");
+
+    // Be wary as new RC frames are being received as this
+    // is being displayed so data may be from overlapping frames
+
+    for ( s = 0; s < RC_CONTROLS ; s++ ) {
+        TxChar(s+'1');
+        TxString(": ");
+        TxChar(RxChMnem[RMap[s]]);
+        TxString(":\t");
+
+        TxVal32((int32)PPM[s] + 1000, 3, 0);
+        TxChar(HT);
+        TxVal32(PPM[s] / 10, 0, '%');
+        if ( ( PPM[s] < -200 ) || ( PPM[s] > 1200 ) )
+            TxString(" FAIL");
+
+        TxNextLine();
+    }
+
+    TxString("Glitches:\t");
+    TxVal32(RCGlitches,0,0);
+    TxNextLine();
+
+} // ReceiverTest
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sb_globals.cpp	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,42 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+/* Module globals, defined here rather than as private
+   variables in the class so the C interrupt routine can
+   access these variables rather than trying to discover 
+   where they are at runtime. */
+char *_tx_buffer[4];
+int   _tx_buffer_size[4];
+int   _tx_buffer_in[4];
+int   _tx_buffer_out[4];
+bool  _tx_buffer_full[4];
+bool  _tx_buffer_overflow[4];
+bool  _tx_buffer_used_malloc[4];
+
+char *_rx_buffer[4];        
+int   _rx_buffer_size[4];
+int   _rx_buffer_in[4];
+int   _rx_buffer_out[4];
+bool  _rx_buffer_full[4];
+bool  _rx_buffer_overflow[4];
+bool  _rx_buffer_used_malloc[4];
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sb_globals.h	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,62 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+#ifndef SB_GLOBALS_G
+#define SB_GLOBALS_G
+
+#define SERIALBUFFERED_BUFFER_SIZE 256
+
+#define SET_REGISTER(reg, val)  *(uint32_t *)(uart_base+reg)=val
+#define GET_REGISTER(reg)       *(uint32_t *)(uart_base+reg)
+
+#define SERIALBUFFERED_RBR  0x00
+#define SERIALBUFFERED_THR  0x00
+#define SERIALBUFFERED_DLL  0x00
+#define SERIALBUFFERED_IER  0x04
+#define SERIALBUFFERED_DML  0x04
+#define SERIALBUFFERED_IIR  0x08
+#define SERIALBUFFERED_FCR  0x08
+#define SERIALBUFFERED_LCR  0x0C
+#define SERIALBUFFERED_LSR  0x14
+#define SERIALBUFFERED_SCR  0x1C
+#define SERIALBUFFERED_ACR  0x20
+#define SERIALBUFFERED_ICR  0x24
+#define SERIALBUFFERED_FDR  0x28
+#define SERIALBUFFERED_TER  0x30
+
+extern char *_tx_buffer[4];
+extern int   _tx_buffer_size[4];
+extern int   _tx_buffer_in[4];
+extern int   _tx_buffer_out[4];
+extern bool  _tx_buffer_full[4];
+extern bool  _tx_buffer_overflow[4];
+extern bool  _tx_buffer_used_malloc[4];
+
+extern char *_rx_buffer[4];        
+extern int   _rx_buffer_size[4];
+extern int   _rx_buffer_in[4];
+extern int   _rx_buffer_out[4];
+extern bool  _rx_buffer_full[4];
+extern bool  _rx_buffer_overflow[4];
+extern bool  _rx_buffer_used_malloc[4];
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serial.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,279 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+// USART routines
+
+// Much of this legacy code to support UAVPset, the original GUI for UAVP.
+// It is to be replaced by packet based comms ASAP.
+
+
+void TxString(const uint8*);
+void TxChar(uint8);
+void TxValU(uint8);
+void TxValS(int8);
+void TxBin8(uint8);
+void TxNextLine(uint8);
+void TxNibble( uint8);
+void TxValH( uint8);
+void TxValH16( uint16);
+uint8 RxChar(void);
+uint8 PollRxChar(void);
+uint8 RxNumU(void);
+int8 RxNumS(void);
+void TxVal32(int32, int8, uint8);
+void TxChar( uint8);
+void TxESCu8( uint8);
+void Sendi16( int16);
+void TxESCi8( int8);
+void TxESCi16( int16);
+void TxESCi24( int24);
+void TxESCi32( int32);
+
+void TxString(const uint8 *pch) {
+    while ( *pch != '\0' )
+        TxChar(*pch++);
+} // TxString
+
+void TxChar(uint8 ch) {
+
+    TxCheckSum ^= ch;
+
+    while ( !TelemetrySerial.writeable() ) {};
+    TelemetrySerial.putc(ch);
+
+    if ( EchoToLogFile )
+        TxLogChar(ch);
+
+} // TxChar
+
+void TxValU(uint8 v) {
+    // UAVPSet requires 3 digits exactly ( 000 to 999 )
+    TxChar((v / 100) + '0');
+    v %= 100;
+
+    TxChar((v / 10) + '0');
+    v %= 10;
+
+    TxChar(v + '0');
+} // TxValU
+
+void TxValS(int8 v) {
+    // UAVPSet requires sign and 3 digits exactly (-999 to 999)
+    if ( v < 0 ) {
+        TxChar('-');    // send sign
+        v = -v;
+    } else
+        TxChar('+');    // send sign
+
+    TxValU(v);
+} // TxValS
+
+void TxNextLine(void) {
+    TxChar(CR);
+    TxChar(LF);
+} // TxNextLine
+
+void TxBin8(uint8 v) {
+
+    static uint8 i;
+
+    for  (i = 0; i <8; i++) {
+        if ( v & 0x80 )
+            TxChar('1');
+        else TxChar('0');
+        v <<= 1;
+    }
+} // TxBin8
+
+void TxNibble(uint8 v) {
+    if ( v > (uint8)9)
+        TxChar('A' + v - 10);
+    else
+        TxChar('0' + v);
+} // TxNibble
+
+void TxValH(uint8 v) {
+    TxNibble(v >> 4);
+    TxNibble(v & 0x0f);
+} // TxValH
+
+void TxValH16(uint16 v) {
+    TxValH(v >> 8);
+    TxValH(v);
+} // TxValH16
+
+uint8 PollRxChar(void) {
+    uint8    ch;
+
+    if (  TelemetrySerial.readable() ) {    // a character is waiting in the buffer
+        ch = TelemetrySerial.getc();        // get the character
+        TxChar(ch);                         // echo it for UAVPSet
+        return(ch);                         // and return it
+    }
+    return( NUL );    // nothing in buffer
+
+} // PollRxChar
+
+uint8 RxChar(void) {
+    uint8    ch;
+
+    while ( !TelemetrySerial.readable() ) {};
+
+    ch = TelemetrySerial.getc();    // get the character
+
+    return(ch);
+} // RxChar
+
+
+uint8 RxNumU(void) {
+    // UAVPSet sends 2 digits
+    uint8 ch;
+    uint8 n;
+
+    n = 0;
+    do
+        ch = PollRxChar();
+    while ( (ch < '0') || (ch > '9') );
+    n = (ch - '0') * 10;
+    do
+        ch = PollRxChar();
+    while ( (ch < '0') || (ch > '9') );
+    n += ch - '0';
+    return(n);
+} // RxNumU
+
+
+int8 RxNumS(void) {
+    // UAVPSet sends sign and 2 digits
+    uint8 ch;
+    int8 n;
+    boolean Neg;
+    n = 0;
+
+    Neg = false;
+    do
+        ch = PollRxChar();
+    while ( ((ch < '0') || (ch > '9')) &&
+            (ch != '-') );
+    if ( ch == '-' ) {
+        Neg = true;
+        do
+            ch = PollRxChar();
+        while ( (ch < '0') || (ch > '9') );
+    }
+    n = (ch - '0') * 10;
+
+    do
+        ch = PollRxChar();
+    while ( (ch < '0') || (ch > '9') );
+    n += ch - '0';
+    if ( Neg )
+        n = -n;
+    return(n);
+} // RxNumS
+
+void TxVal32(int32 V, int8 dp, uint8 Separator) {
+    uint8 S[16];
+    int8 c,  zeros, i;
+    int32 NewV, Rem;
+
+    if (V<0) {
+        TxChar('-');
+        V=-V;
+    }
+//    else
+//        TxChar(' ');
+
+    c=0;
+    do {
+        NewV=V/10;
+        Rem=V-(NewV*10);
+        S[c++]=Rem + '0';
+        V=NewV;
+    } while (V>0);
+
+    if ((c < ( dp + 1 ) ) && (dp > 0 )) {
+        TxChar('0');
+        TxChar('.');
+    }
+
+    zeros = (int8)dp-c-1;
+    if ( zeros >= 0 )
+        for (i = zeros; i>=0; i--)
+            TxChar('0');
+
+    do {
+        c--;
+        TxChar(S[c]);
+        if ((c==dp)&&(c>0))
+            TxChar('.');
+    } while ( c > 0 );
+
+    if ( Separator != NUL )
+        TxChar(Separator);
+} // TxVal32
+
+void TxESCu8(uint8 ch) {
+    if ((ch==SOH)||(ch==EOT)||(ch==ESC))
+        TxChar(ESC);
+    TxChar(ch);
+} // TxESCu8
+
+void TxESCi8(int8 b) {
+    if (((uint8)b==SOH)||((uint8)b==EOT)||((uint8)b==ESC))
+        TxChar(ESC);
+    TxChar(b);
+} // TxESCu8
+
+void Sendi16(int16 v) {
+    i16u Temp;
+
+    Temp.i16 = v;
+    TxChar(Temp.b0);
+    TxChar(Temp.b1);
+} // Sendi16
+
+void TxESCi16(int16 v) {
+    i16u Temp;
+
+    Temp.i16 = v;
+    TxESCu8(Temp.b0);
+    TxESCu8(Temp.b1);
+} // Sendi16
+
+void TxESCi24(int24 v) {
+    i24u Temp;
+
+    Temp.i24 = v;
+    TxESCu8(Temp.b0);
+    TxESCu8(Temp.b1);
+    TxESCu8(Temp.b2);
+} // Sendi16
+
+void TxESCi32(int32 v) {
+    i32u Temp;
+
+    Temp.i32 = v;
+    TxESCi16(Temp.w0);
+    TxESCi16(Temp.w1);
+} // TxESCi32
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stats.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,137 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+void ZeroStats(void);
+void ReadStatsPX(void);
+void WriteStatsPX(void);
+void ShowStats(void);
+
+int16     Stats[MAX_STATS];
+
+#define INIT_MIN 1000L
+
+void ZeroStats(void)
+{
+    int8 s;
+
+    for (s = 0 ; s < MAX_STATS ; s++ )
+        Stats[s] = 0;
+
+    Stats[MinHDiluteS] = INIT_MIN;
+    Stats[MaxHDiluteS] = 0;
+    Stats[MinROCS] = INIT_MIN;
+    Stats[MaxROCS] = 0;
+    Stats[GPSMinSatsS] = INIT_MIN;
+    Stats[GPSMaxSatsS] = 0;
+    Stats[MinTempS] = INIT_MIN;
+    Stats[MaxTempS] = 0;
+
+} // ZeroStats
+
+void ReadStatsPX(void)
+{
+    int8 s;
+
+    for (s = 0 ; s < MAX_STATS ; s++ )
+        Stats[s] = Read16PX(STATS_ADDR_PX + s*2);
+} // InitStats
+
+void WriteStatsPX()
+{
+    int8 s, i;
+    int16 Temp;
+
+    if ( P[ESCType] != ESCPPM )
+        for ( i = 0; i < NoOfI2CESCOutputs; i++ )
+            Stats[ESCI2CFailS] += ESCI2CFail[i];
+
+    for (s = 0 ; s < MAX_STATS ; s++ )
+        Write16PX(STATS_ADDR_PX + s*2, Stats[s]);
+
+    Temp = ToPercent(CruiseThrottle, OUT_MAXIMUM);
+    WritePX(PercentCruiseThr, Temp);
+
+} // WriteStatsPX
+
+void ShowStats(void)
+{
+    TxString("\r\nFlight Statistics\r\n");
+
+    if ( Stats[BadS] != 0 )
+    {
+        TxString("Misc(gke):     \t");TxVal32((int32)Stats[BadS],0,' '); TxVal32((int32)Stats[BadNumS],0,' ');TxNextLine();
+    }
+
+    TxString("\r\nSensor/Rx Failures (Count)\r\n");
+    TxString("I2CBus:   \t");TxVal32((int32)Stats[I2CFailS],0,0); TxNextLine();
+    TxString("GPS:      \t");TxVal32((int32)Stats[GPSInvalidS],0,0); TxNextLine();
+    TxString("Acc:      \t");TxVal32((int32)Stats[AccFailS], 0, 0); TxNextLine();
+    TxString("Gyro:     \t");TxVal32((int32)Stats[GyroFailS], 0, 0); TxNextLine();
+    TxString("Comp:     \t");TxVal32((int32)Stats[CompassFailS], 0, 0); TxNextLine();
+    TxString("Baro:     \t");TxVal32((int32)Stats[BaroFailS],0 , 0); TxNextLine();
+    if ( P[ESCType] != ESCPPM )
+    {
+        TxString("I2CESC:   \t");TxVal32((int32)Stats[ESCI2CFailS],0 , 0); TxNextLine();
+    }
+    TxString("Rx:       \t");TxVal32((int32)Stats[RCGlitchesS],0,' '); TxNextLine(); 
+    TxString("Failsafes:\t");TxVal32((int32)Stats[RCFailsafesS],0,' '); TxNextLine();
+    
+    TxString("\r\nBaro\r\n"); // can only display to 3276M
+    TxString("Alt:      \t");TxVal32((int32)Stats[BaroRelAltitudeS], 1, ' '); TxString("M \r\n");
+    if ( Stats[MinROCS] < INIT_MIN )
+    {
+        TxString("ROC:      \t");TxVal32((int32)Stats[MinROCS], 1, ' '); 
+                            TxVal32((int32)Stats[MaxROCS], 1, ' '); TxString("M/S\r\n");
+    }
+    
+    if ( Stats[MinTempS] < INIT_MIN )
+    {
+        TxString("Ambient:  \t");TxVal32((int32)Stats[MinTempS], 1, ' '); 
+                            TxVal32((int32)Stats[MaxTempS], 1, ' '); TxString("C\r\n");
+    }
+
+    TxString("\r\nGPS\r\n");
+    TxString("Alt:      \t");TxVal32((int32)Stats[GPSAltitudeS], 1, ' '); TxString("M\r\n");
+    #ifdef GPS_INC_GROUNDSPPXD 
+    TxString("Vel:      \t");TxVal32(ConvertGPSToM((int32)Stats[GPSVelS]), 1, ' '); TxString("M/S\r\n"); 
+    #endif // GPS_INC_GROUNDSPPXD
+
+    if ( Stats[GPSMinSatsS] < INIT_MIN )
+    {
+        TxString("Sats:     \t");TxVal32((int32)Stats[GPSMinSatsS], 0, ' ');
+        TxVal32((int32)Stats[GPSMaxSatsS], 0, 0); TxNextLine();
+    }
+
+    if ( Stats[MinHDiluteS] < INIT_MIN )
+    {
+        TxString("HDilute:  \t");TxVal32((int32)Stats[MinHDiluteS], 2, ' ');
+        TxVal32((int32)Stats[MaxHDiluteS], 2, 0); TxNextLine();
+    }
+
+    if ( Stats[NavValidS] )
+        TxString("Navigation ENABLED\r\n");    
+    else
+        TxString("Navigation DISABLED (No fix at launch)\r\n");
+       
+} // ShowStats
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/telemetry.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,613 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+void RxTelemetryPacket(uint8);
+void InitTelemetryPacket(void);
+void BuildTelemetryPacket(uint8);
+
+void SendPacketHeader(void);
+void SendPacketTrailer(void);
+
+void SendTelemetry(void);
+void SendCycle(void);
+void SendControl(void);
+void SendFlightPacket(void);
+void SendNavPacket(void);
+void SendControlPacket(void);
+void SendStatsPacket(void);
+void SendParamPacket(uint8);
+void SendMinPacket(void);
+void SendArduStation(void);
+void SendCustom(void);
+void SensorTrace(void);
+
+uint8 UAVXCurrPacketTag;
+uint8 RxPacketLength, RxPacketByteCount;
+uint8 RxCheckSum;
+uint8 RxPacketTag, ReceivedPacketTag;
+uint8 PacketRxState;
+boolean CheckSumError, TelemetryPacketReceived;
+
+int16 RxLengthErrors, RxTypeErrors, RxCheckSumErrors;
+
+uint8 UAVXPacket[256];
+
+FILE *logfile = NULL;
+boolean EchoToLogFile = false;
+uint32 LogChars;
+boolean LogfileIsOpen = false;
+
+uint8 TxCheckSum;
+
+void InitTelemetryPacket(void) {
+    RxPacketByteCount = 0;
+    RxCheckSum = 0;
+    RxPacketTag = UnknownPacketTag;
+    RxPacketLength = 2; // set as minimum
+    PacketRxState = WaitRxSentinel;
+} // InitTelemetryPacket
+
+void BuildTelemetryPacket(uint8 ch) {
+    static boolean RxPacketError;
+
+    UAVXPacket[RxPacketByteCount++] = ch;
+
+    if (RxPacketByteCount == 1) {
+        RxPacketTag = ch;
+        PacketRxState=WaitRxBody;
+    } else
+        if (RxPacketByteCount == 2) {
+            RxPacketLength = ch; // ignore
+            PacketRxState = WaitRxBody;
+        } else
+            if (RxPacketByteCount >= (RxPacketLength + 3)) {
+                RxPacketError = CheckSumError = RxCheckSum != 0;
+
+                if (CheckSumError)
+                    RxCheckSumErrors++;
+
+                if (!RxPacketError) {
+                    TelemetryPacketReceived = true;
+                    ReceivedPacketTag=RxPacketTag;
+                }
+                PacketRxState = WaitRxSentinel;
+                //   InitPollPacket();
+            } else
+                PacketRxState = WaitRxBody;
+} // BuildTelemetryPacket
+
+void RxTelemetryPacket(uint8 ch) {
+
+    RxCheckSum ^= ch;
+    switch (PacketRxState) {
+        case WaitRxSentinel:
+            if (ch == SOH) {
+                InitTelemetryPacket();
+                CheckSumError = false;
+                PacketRxState = WaitRxBody;
+            }
+            break;
+        case WaitRxBody:
+            if (ch == ESC)
+                PacketRxState = WaitRxESC;
+            else
+                if (ch == SOH) { // unexpected start of packet
+                    RxLengthErrors++;
+
+                    InitTelemetryPacket();
+                    PacketRxState = WaitRxBody;
+                } else
+                    if (ch == EOT) { // unexpected end of packet
+                        RxLengthErrors++;
+                        PacketRxState = WaitRxSentinel;
+                    } else
+                        BuildTelemetryPacket(ch);
+            break;
+        case WaitRxESC:
+            BuildTelemetryPacket(ch);
+            break;
+        default:
+            PacketRxState = WaitRxSentinel;
+            break;
+    }
+} // ParseTelemetryPacket
+
+
+#define NAV_STATS_INTERLEAVE    10
+static int8 StatsNavAlternate = 0;
+
+void CheckTelemetry(void) {
+
+    // check incoming - switch on associated action
+
+    // do routine telemetry Tx
+    if ( mSClock() > mS[TelemetryUpdate] )
+        switch ( P[TelemetryType] ) {
+            case UAVXTelemetry:
+                mS[TelemetryUpdate] = mSClock() + UAVX_TEL_INTERVAL_MS;
+                SendCycle();
+                break;
+            case ArduStationTelemetry:
+                mS[TelemetryUpdate] = mSClock() + UAVX_CONTROL_TEL_INTERVAL_MS;
+                SendArduStation();
+                break;
+            case UAVXControlTelemetry:
+                mS[TelemetryUpdate] = mSClock() + UAVX_CONTROL_TEL_INTERVAL_MS;
+                SendControlPacket();
+                break;
+            case UAVXMinTelemetry:
+                mS[TelemetryUpdate] = mSClock() + UAVX_MIN_TEL_INTERVAL_MS;
+                SendMinPacket();
+                break;
+            case CustomTelemetry:
+                mS[TelemetryUpdate] = mSClock() + CUSTOM_TEL_INTERVAL_MS;
+                SendCustom();
+                break;
+            case GPSTelemetry:
+                break;
+        }
+
+} // CheckTelemetry
+
+void SendPacketHeader(void) {
+    static int8 b;
+
+    EchoToLogFile = true;
+
+#ifdef TELEMETRY_PREAMBLE
+    for (b=10;b;b--)
+        TxChar(0x55);
+#endif // TELEMETRY_PREAMBLE
+
+    TxChar(0xff); // synchronisation to "jolt" USART
+    TxChar(SOH);
+    TxCheckSum = 0;
+} // SendPacketHeader
+
+void SendPacketTrailer(void) {
+    TxESCu8(TxCheckSum);
+    TxChar(EOT);
+
+    TxChar(CR);
+    TxChar(LF);
+
+    EchoToLogFile = false;
+} // SendPacketTrailer
+
+void ShowAttitude(void) {
+    // Stick units
+    TxESCi16(DesiredRoll);
+    TxESCi16(DesiredPitch);
+    TxESCi16(DesiredYaw);
+
+    // mRadian and mG
+    TxESCi16(Gyro[Roll] * 1000.0); // Rate
+    TxESCi16(Gyro[Pitch] * 1000.0);
+    TxESCi16(Gyro[Yaw] * 1000.0);
+
+    TxESCi16(Angle[Roll] * 1000.0);
+    TxESCi16(Angle[Pitch] * 1000.0);
+    TxESCi16(Angle[Yaw] * 1000.0);
+
+    TxESCi16(Acc[LR] * 1000.0);
+    TxESCi16(Acc[BF] * 1000.0);
+    TxESCi16(Acc[UD] * 1000.0);
+} // ShowAttitude
+
+void SendFlightPacket(void) {
+    static int8 b;
+
+    SendPacketHeader();
+
+    TxESCu8(UAVXFlightPacketTag);
+    TxESCu8(48 + TELEMETRY_FLAG_BYTES);
+    for ( b = 0; b < TELEMETRY_FLAG_BYTES; b++ )
+        TxESCu8(F.AllFlags[b]);
+
+    TxESCu8(State);
+
+    // dV, dA, mAH
+    TxESCi16(BatteryVolts * 10.0); // to do scaling
+    TxESCi16(BatteryCurrent * 10.0);
+    TxESCi16(BatteryChargeUsedAH * 1000.0);
+
+    TxESCi16(RCGlitches);
+    TxESCi16(DesiredThrottle);
+
+    ShowAttitude();
+
+    TxESCi8((int8)Comp[LR]);
+    TxESCi8((int8)Comp[BF]);
+    TxESCi8((int8)Comp[UD]);
+    TxESCi8((int8)Comp[Alt]);
+
+    for ( b = 0; b < 4; b++ )
+        TxESCu8((uint8)PWM[b]);
+
+    TxESCu8((uint8)PWM[CamRollC]);
+    TxESCu8((uint8)PWM[CamPitchC]);
+
+    TxESCi24(mSClock() - mS[StartTime]);
+
+    SendPacketTrailer();
+} // SendFlightPacket
+
+void SendControlPacket(void) {
+    static int8 b;
+
+    SendPacketHeader();
+
+    TxESCu8(UAVXControlPacketTag);
+    TxESCu8(35);
+
+    TxESCi16(DesiredThrottle);
+
+    ShowAttitude();
+
+    for ( b = 0; b < 6; b++ ) // motor/servo channels
+        TxESCu8((uint8)PWM[b]);
+
+    TxESCi24( time(NULL) );
+
+    SendPacketTrailer();
+
+} // SendControlPacket
+
+void SendNavPacket(void) {
+    SendPacketHeader();
+
+    TxESCu8(UAVXNavPacketTag);
+    TxESCu8(59);
+
+    TxESCu8(NavState);
+    TxESCu8(FailState);
+    TxESCu8(GPSNoOfSats);
+    TxESCu8(GPSFix);
+
+    TxESCu8(CurrWP);
+
+    TxESCi16(ROC * 10.0 );                         // dm/S
+    TxESCi24(BaroRelAltitude * 10.0);
+
+    TxESCi16(GPSHeading * 1000.0);
+    TxESCi16(RangefinderAltitude * 100.0);          // cm
+
+    TxESCi16(GPSHDilute);
+    TxESCi16(Heading * 1000.0);
+    TxESCi16(WayHeading * 1000.0);
+
+    TxESCi16(GPSVel * 10.0);
+    TxESCi16(0);                                   // was GPSROC;
+
+    TxESCi24(GPSRelAltitude * 10.0);               // dm
+    TxESCi32(GPSLatitude);                         // 5 decimal minute units
+    TxESCi32(GPSLongitude);
+
+    TxESCi24(DesiredAltitude * 10.0 );
+    TxESCi32(DesiredLatitude);
+    TxESCi32(DesiredLongitude);
+
+    TxESCi24(mS[NavStateTimeout] - mSClock());    // mS
+
+    TxESCi16(AmbientTemperature.i16);             // 0.1C
+    TxESCi32( time(NULL) );                       //GPSSeconds);
+
+    TxESCu8(NavSensitivity);
+    TxESCi8(NavCorr[Roll]);
+    TxESCi8(NavCorr[Pitch]);
+    TxESCi8(NavCorr[Yaw]);
+
+    SendPacketTrailer();
+
+} // SendNavPacket
+
+void SendStatsPacket(void) {
+    SendPacketHeader();
+
+    TxESCu8(UAVXStatsPacketTag);
+    TxESCu8(44);
+
+    TxESCi16(Stats[I2CFailS]);
+    TxESCi16(Stats[GPSInvalidS]);
+    TxESCi16(Stats[AccFailS]);
+    TxESCi16(Stats[GyroFailS]);
+    TxESCi16(Stats[CompassFailS]);
+    TxESCi16(Stats[BaroFailS]);
+    TxESCi16(Stats[ESCI2CFailS]);
+
+    TxESCi16(Stats[RCFailsafesS]);
+
+    TxESCi16(Stats[GPSAltitudeS]);
+    TxESCi16(Stats[GPSVelS]);
+    TxESCi16(Stats[GPSMinSatsS]);
+    TxESCi16(Stats[GPSMaxSatsS]);
+    TxESCi16(Stats[MinHDiluteS]);
+    TxESCi16(Stats[MaxHDiluteS]);
+
+    TxESCi16(Stats[BaroRelAltitudeS]);
+    TxESCi16(0);//Stats[MinBaroROCS]);
+    TxESCi16(0);//Stats[MaxBaroROCS]);
+
+    TxESCi16(Stats[MinTempS]);
+    TxESCi16(Stats[MaxTempS]);
+
+    TxESCi16(Stats[BadS]);
+
+    TxESCu8(UAVXAirframe | 0x80);
+    TxESCu8(Orientation);
+    TxESCi16(Stats[BadNumS]);
+
+    SendPacketTrailer();
+
+} // SendStatsPacket
+
+void SendMinPacket(void) {
+    static int8 b;
+
+    SendPacketHeader();
+
+    TxESCu8(UAVXMinPacketTag);
+    TxESCu8(33 + TELEMETRY_FLAG_BYTES);
+    for ( b = 0; b < TELEMETRY_FLAG_BYTES; b++ )
+        TxESCu8(F.AllFlags[b]);
+
+    TxESCu8(State);
+    TxESCu8(NavState);
+    TxESCu8(FailState);
+    
+    TxESCi16(BatteryVolts * 10.0); // to do scaling
+    TxESCi16(BatteryCurrent * 10.0);
+    TxESCi16(BatteryChargeUsedAH * 1000.0);
+
+    TxESCi16(Angle[Roll] * 1000.0);
+    TxESCi16(Angle[Pitch] * 1000.0);
+
+    TxESCi24(BaroRelAltitude * 10.0);
+    TxESCi16(RangefinderAltitude * 100.0);                 // cm
+
+    TxESCi16(Heading * 1000.0);
+
+    TxESCi32(GPSLatitude);                         // 5 decimal minute units
+    TxESCi32(GPSLongitude);
+
+    TxESCu8(UAVXAirframe | 0x80 ); // ARM has top bit set
+    TxESCu8(Orientation);
+
+    TxESCi24(mSClock() - mS[StartTime]);
+
+    SendPacketTrailer();
+
+} // SendMinPacket
+
+void SendParamPacket(uint8 p) {
+
+    static uint8 b;
+
+    SendPacketHeader();
+
+    TxESCu8(UAVXParamsPacketTag);
+    TxESCu8(MAX_PARAMETERS+1);
+    TxESCu8(p);
+    for (b = 0; b < (uint8)MAX_PARAMETERS; b++ )
+        TxESCi8(PX[MAX_PARAMETERS*2 + b]);
+
+    SendPacketTrailer();
+
+} // SendParamPacket
+
+void SendCycle(void) { 
+
+    switch ( UAVXCurrPacketTag ) {
+        case UAVXFlightPacketTag:
+            SendFlightPacket();
+
+            UAVXCurrPacketTag = UAVXNavPacketTag;
+            break;
+
+        case UAVXNavPacketTag:
+            if ( ++StatsNavAlternate < NAV_STATS_INTERLEAVE)
+                SendNavPacket();
+            else {
+                SendStatsPacket();
+                StatsNavAlternate = 0;
+            }
+
+            UAVXCurrPacketTag = UAVXFlightPacketTag;
+            break;
+
+        default:
+            UAVXCurrPacketTag = UAVXFlightPacketTag;
+            break;
+    }
+
+} // SendCycle
+
+void SendArduStation(void) {
+
+    static int8 Count = 0;
+    /*
+    Definitions of the low rate telemetry (1Hz):
+    LAT: Latitude
+    LON: Longitude
+    SPD: Speed over ground from GPS
+    CRT: Climb Rate in M/S
+    ALT: Altitude in meters
+    ALH: The altitude is trying to hold
+    CRS: Course over ground in degrees.
+    BER: Bearing is the heading you want to go
+    WPN: Waypoint number, where WP0 is home.
+    DST: Distance from Waypoint
+    BTV: Battery Voltage.
+    RSP: Roll setpoint used to debug, (not displayed here).
+
+    Definitions of the high rate telemetry (~4Hz):
+    ASP: Airspeed, right now is the raw data.
+    TTH: Throttle in 100% the autopilot is applying.
+    RLL: Roll in degrees + is right - is left
+    PCH: Pitch in degrees
+    SST: Switch Status, used for debugging, but is disabled in the current version.
+    */
+
+    if ( ++Count == 4 ) { 
+        TxString("!!!");
+        TxString("LAT:");
+        TxVal32(GPSLatitude / 6000, 3, 0);
+        TxString(",LON:");
+        TxVal32(GPSLongitude / 6000, 3, 0);
+        TxString(",ALT:");
+        TxVal32(Altitude / 10,0,0);
+        TxString(",ALH:");
+        TxVal32(DesiredAltitude / 10, 0, 0);
+        TxString(",CRT:");
+        TxVal32(ROC / 100, 0, 0);
+        TxString(",CRS:");
+        TxVal32(Heading * RADDEG, 0, 0); // scaling to degrees?
+        TxString(",BER:");
+        TxVal32(WayHeading * RADDEG, 0, 0);
+        TxString(",SPD:");
+        TxVal32(GPSVel, 0, 0);
+        TxString(",WPN:");
+        TxVal32(CurrWP,0,0);
+        TxString(",DST:");
+        TxVal32(0, 0, 0); // distance to WP
+        TxString(",BTV:");
+        TxVal32((BatteryVoltsADC * 61)/205, 1, 0);
+        TxString(",RSP:");
+        TxVal32(DesiredRoll, 0, 0);
+
+        Count = 0;
+    } else {
+        TxString("+++");
+        TxString("ASP:");
+        TxVal32(GPSVel / 100, 0, 0);
+        TxString(",RLL:");
+        TxVal32(Angle[Roll] / 35, 0, 0); // scale to degrees?
+        TxString(",PCH:");
+        TxVal32(Angle[Pitch] / 35, 0, 0);
+        TxString(",THH:");
+        TxVal32( ((int24)DesiredThrottle * 100L) / RC_MAXIMUM, 0, 0);
+    }
+
+    TxString(",***\r\n");
+
+} // SendArduStation
+
+void SendCustom(void)
+{ // user defined telemetry human readable OK for small amounts of data < 1mS
+
+    EchoToLogFile = true;
+
+    // insert values here using TxVal32(n, dp, separator)
+    // dp is the scaling to decimal places, separator
+    // separator may be a single 'char', HT for tab, or 0 (no space)
+    // ->
+
+    TxVal32(mSClock(), 3, HT);
+
+    if ( F.HoldingAlt ) // are we holding
+        TxChar('H');
+    else
+        TxChar('N');
+    TxChar(HT);
+
+    if (F.UsingRangefinderAlt ) // are we using the rangefinder
+        TxChar('R');
+    else
+        TxChar('B');
+    TxChar(HT);
+
+    TxVal32(SRS32(Comp[Alt],1), 1, HT);        // ~% throttle compensation
+
+    TxVal32(GPSRelAltitude, 1, HT);
+    TxVal32(BaroRelAltitude, 1, HT);
+    TxVal32(RangefinderAltitude, 2, HT);
+
+    TxVal32(BaroPressure, 0, HT);            // eff. sensor reading
+    TxVal32(BaroTemperature, 0, HT);         // eff. sensor reading redundant for MPX4115
+    TxVal32(CompBaroPressure, 0, HT);          // moving sum of last 8 readings
+
+    // <-
+
+    TxChar(CR);
+    TxChar(LF);
+
+    EchoToLogFile = false;
+} // SendCustom
+
+void SensorTrace(void) {
+#ifdef TESTING
+
+    if ( DesiredThrottle > 20 ) {
+        EchoToLogFile = false; // direct to USART
+
+        TxValH16(((int24)Heading * 180)/MILLIPI);
+        TxChar(';');
+
+        TxValH16(BaroRelAltitude);
+        TxChar(';');
+        TxValH16(RangefinderAltitude);
+        TxChar(';');
+        TxValH16(0);
+        TxChar(';');
+
+        TxValH16(DesiredThrottle);
+        TxChar(';');
+        TxValH16(DesiredRoll);
+        TxChar(';');
+        TxValH16(DesiredPitch);
+        TxChar(';');
+        TxValH16(DesiredYaw);
+        TxChar(';');
+
+        TxValH16(Rate[Roll]);
+        TxChar(';');
+        TxValH16(Rate[Pitch]);
+        TxChar(';');
+        TxValH16(Rate[Yaw]);
+        TxChar(';');
+
+        TxValH16(Angle[Roll]);
+        TxChar(';');
+        TxValH16(Angle[Pitch]);
+        TxChar(';');
+        TxValH16(Angle[Yaw]);
+        TxChar(';');
+
+        TxValH16(Acc[LR]);
+        TxChar(';');
+        TxValH16(Acc[FB]);
+        TxChar(';');
+        TxValH16(Acc[DU]);
+        TxChar(';');
+
+        TxValH16(Comp[LR]);
+        TxChar(';');
+        TxValH16(Comp[FB]);
+        TxChar(';');
+        TxValH16(Comp[DU]);
+        TxChar(';');
+        TxValH16(Comp[Alt]);
+        TxChar(';');
+        TxNextLine();
+    }
+#endif // TESTING
+} // SensorTrace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/temperature.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,71 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+void GetTemperature(void);
+void InitTemperature(void);
+
+i16u AmbientTemperature;
+
+void GetTemperature(void) {
+
+    I2CTEMP.start();
+    if ( I2CTEMP.write(TMP100_RD) != I2C_ACK ) goto Terror;
+    AmbientTemperature.b1 = I2CTEMP.read(I2C_ACK);
+    AmbientTemperature.b0 = I2CTEMP.read(I2C_NACK);
+    I2CTEMP.stop();
+
+    // Top 9 bits 0.5C res. scale to 0.1C
+    AmbientTemperature.i16 = SRS16(    AmbientTemperature.i16, 7) * 5;
+    if ( AmbientTemperature.i16 > Stats[MaxTempS])
+        Stats[MaxTempS] = AmbientTemperature.i16;
+    else
+        if ( AmbientTemperature.i16 < Stats[MinTempS] )
+            Stats[MinTempS] = AmbientTemperature.i16;
+    return;
+
+Terror:
+    I2CTEMP.stop();
+    AmbientTemperature.i16 = 0;
+
+    return;
+} // GetTemperature
+
+void InitTemperature(void) {
+    I2CTEMP.start();
+    if(  I2CTEMP.write(TMP100_WR) != I2C_ACK ) goto Terror;
+    if(  I2CTEMP.write(TMP100_CMD) != I2C_ACK ) goto Terror;
+    if(  I2CTEMP.write(TMP100_CFG) != I2C_ACK ) goto Terror;
+    I2CTEMP.stop();
+
+    I2CTEMP.start();
+    if( I2CTEMP.write(TMP100_WR) != I2C_ACK ) goto Terror;
+    if(  I2CTEMP.write(TMP100_TMP) != I2C_ACK ) goto Terror; // Select temperature
+    I2CTEMP.stop();
+
+    GetTemperature();
+    
+    return;
+    
+ Terror:
+    I2CTEMP.stop();
+    AmbientTemperature.i16 = 0;
+
+} // InitTemperature
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uavx_aileron.h	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,97 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+ const int8 DefaultParams[MAX_PARAMETERS][2] = {
+    {20,0},            // RollKp,             01
+    {12,0},             // RollKi,            02
+    {50, 0},            // RollKd,            03
+    {0,true},            // HorizDampKp,        04c //-1
+    {5,0},                 // RollIntLimit,    05
+    {20,0},             // PitchKp,            06
+    {12,0},             // PitchKi,            07
+    {50,0},                 // PitchKd,            08
+    {8,0},                 // AltKp,            09
+    {5,0},                 // PitchIntLimit,    10
+    
+    {30,0},             // YawKp,             11
+    {25,0},             // YawKi,            12
+    {0,0},                 // YawKd,            13
+    {25,0},                 // YawLimit,        14
+    {2,0},                 // YawIntLimit,        15
+    {8,true},             // ConfigBits,        16c
+    {0,true},            // was TimeSlots,   17c
+    {48,true},             // LowVoltThres,    18c
+    {20,true},             // CamRollKp,        19c
+    {45,true},             // PercentCruiseThr,20c 
+    
+    {0,true},             // VertDampKp,        21c //-1
+    {0,true},             // MiddleDU,        22c
+    {20,true},             // PercentIdleThr,    23c
+    {0,true},             // MiddleLR,        24c
+    {0,true},             // MiddleFB,        25c
+    {20,true},             // CamPitchKp,        26c
+    {10,0},             // CompassKp,        27
+    {8,0},                // AltKi,            28
+    {0,0},                 // was NavRadius,    29
+    {8,0},                 // NavKi,            30 
+
+    {0,0},                 // GSThrottle,        31
+    {0,0},                // Acro,              32
+    {10,0},                 // NavRTHAlt,        33
+    {0,true},            // NavMagVar,        34c
+    {ITG3200Gyro,true},     // GyroType,         35c
+    {ESCPPM,true},         // ESCType,            36c
+    {UnknownTxRx,true},         // TxRxType            37c
+    {2,true},                // NeutralRadius    38
+    {30,true},                // PercentNavSens6Ch    39
+    {1,true},            // CamRollTrim,        40c
+
+    {-16,0},            // NavKd            41
+    {1,true},            // VertDampDecay    42c
+    {1,true},            // HorizDampDecay    43c
+    {56,true},            // BaroScale        44c
+    {UAVXTelemetry,true}, // TelemetryType    45c
+    {-8,0},                // MaxDescentRateDmpS     46
+    {30,true},            // DescentDelayS    47c
+    {1,0},                // NavIntLimit        48
+    {2,0},                // AltIntLimit        49
+    {11,true},            // was GravComp        50c
+
+    {0,true},            // was CompSteps    51c
+    {0,true},            // ServoSense        52c    
+    {3,true},            // CompassOffsetQtr 53c
+    {49,true},            // BatteryCapacity    54c    
+    {LY530Gyro,true},    // was GyroYawType    55c        
+    {4,0},                // AltKd            56
+    #if (defined  TRICOPTER) | (defined VTCOPTER )
+    {24,true},                // Orient            57
+    #else    
+    {0,true},                // Orient            57
+    #endif // TRICOPTER | VTCOPTER                
+    
+    {12,true},                // NavYawLimit        58
+    {0,0},                // Balance            59
+    {0,0},                // 60 - 64 unused currently    
+    {0,0},    
+
+    {0,0},    
+    {0,0},    
+    {0,0}                        
+    };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uavx_elevon.h	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,97 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+ const int8 DefaultParams[MAX_PARAMETERS][2] = {
+    {20,0},            // RollKp,             01
+    {12,0},             // RollKi,            02
+    {50, 0},            // RollKd,            03
+    {0,true},            // HorizDampKp,        04c //-1
+    {5,0},                 // RollIntLimit,    05
+    {20,0},             // PitchKp,            06
+    {12,0},             // PitchKi,            07
+    {50,0},                 // PitchKd,            08
+    {8,0},                 // AltKp,            09
+    {5,0},                 // PitchIntLimit,    10
+    
+    {30,0},             // YawKp,             11
+    {25,0},             // YawKi,            12
+    {0,0},                 // YawKd,            13
+    {25,0},                 // YawLimit,        14
+    {2,0},                 // YawIntLimit,        15
+    {8,true},             // ConfigBits,        16c
+    {0,true},            // was TimeSlots,   17c
+    {48,true},             // LowVoltThres,    18c
+    {20,true},             // CamRollKp,        19c
+    {45,true},             // PercentCruiseThr,20c 
+    
+    {0,true},             // VertDampKp,        21c //-1
+    {0,true},             // MiddleDU,        22c
+    {20,true},             // PercentIdleThr,    23c
+    {0,true},             // MiddleLR,        24c
+    {0,true},             // MiddleFB,        25c
+    {20,true},             // CamPitchKp,        26c
+    {10,0},             // CompassKp,        27
+    {8,0},                // AltKi,            28
+    {0,0},                 // was NavRadius,    29
+    {8,0},                 // NavKi,            30 
+
+    {0,0},                 // GSThrottle,        31
+    {0,0},                // Acro,              32
+    {10,0},                 // NavRTHAlt,        33
+    {0,true},            // NavMagVar,        34c
+    {ITG3200Gyro,true},     // GyroType,         35c
+    {ESCPPM,true},         // ESCType,            36c
+    {UnknownTxRx,true},         // TxRxType            37c
+    {2,true},                // NeutralRadius    38
+    {30,true},                // PercentNavSens6Ch    39
+    {1,true},            // CamRollTrim,        40c
+
+    {16,0},            // NavKd            41
+    {1,true},            // VertDampDecay    42c
+    {1,true},            // HorizDampDecay    43c
+    {56,true},            // BaroScale        44c
+    {UAVXTelemetry,true}, // TelemetryType    45c
+    {8,0},                // MaxDescentRateDmpS     46
+    {30,true},            // DescentDelayS    47c
+    {1,0},                // NavIntLimit        48
+    {2,0},                // AltIntLimit        49
+    {11,true},            // was GravComp        50c
+
+    {0,true},            // was CompSteps    51c
+    {0,true},            // ServoSense        52c    
+    {3,true},            // CompassOffsetQtr 53c
+    {49,true},            // BatteryCapacity    54c    
+    {LY530Gyro,true},    // was GyroYawType    55c        
+    {4,0},                // AltKd            56
+    #if (defined  TRICOPTER) | (defined VTCOPTER )
+    {24,true},                // Orient            57
+    #else    
+    {0,true},                // Orient            57
+    #endif // TRICOPTER | VTCOPTER                
+    
+    {12,true},                // NavYawLimit        58
+    {0,0},                // Balance            59
+    {0,0},                // 60 - 64 unused currently    
+    {0,0},    
+
+    {0,0},    
+    {0,0},    
+    {0,0}                        
+    };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uavx_helicopter.h	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,97 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+ const int8 DefaultParams[MAX_PARAMETERS][2] = {
+    {20,0},            // RollKp,             01
+    {12,0},             // RollKi,            02
+    {50, 0},            // RollKd,            03
+    {0,true},            // HorizDampKp,        04c //-1
+    {5,0},                 // RollIntLimit,    05
+    {20,0},             // PitchKp,            06
+    {12,0},             // PitchKi,            07
+    {50,0},                 // PitchKd,            08
+    {8,0},                 // AltKp,            09
+    {5,0},                 // PitchIntLimit,    10
+    
+    {30,0},             // YawKp,             11
+    {25,0},             // YawKi,            12
+    {0,0},                 // YawKd,            13
+    {25,0},                 // YawLimit,        14
+    {2,0},                 // YawIntLimit,        15
+    {8,true},             // ConfigBits,        16c
+    {0,true},            // was TimeSlots,   17c
+    {48,true},             // LowVoltThres,    18c
+    {20,true},             // CamRollKp,        19c
+    {45,true},             // PercentCruiseThr,20c 
+    
+    {0,true},             // VertDampKp,        21c //-1
+    {0,true},             // MiddleDU,        22c
+    {20,true},             // PercentIdleThr,    23c
+    {0,true},             // MiddleLR,        24c
+    {0,true},             // MiddleFB,        25c
+    {20,true},             // CamPitchKp,        26c
+    {10,0},             // CompassKp,        27
+    {8,0},                // AltKi,            28
+    {0,0},                 // was NavRadius,    29
+    {8,0},                 // NavKi,            30 
+
+    {0,0},                 // GSThrottle,        31
+    {0,0},                // Acro,              32
+    {10,0},                 // NavRTHAlt,        33
+    {0,true},            // NavMagVar,        34c
+    {ITG3200Gyro,true},     // GyroType,         35c
+    {ESCPPM,true},         // ESCType,            36c
+    {UnknownTxRx,true},         // TxRxType            37c
+    {2,true},                // NeutralRadius    38
+    {30,true},                // PercentNavSens6Ch    39
+    {1,true},            // CamRollTrim,        40c
+
+    {16,0},            // NavKd            41
+    {1,true},            // VertDampDecay    42c
+    {1,true},            // HorizDampDecay    43c
+    {56,true},            // BaroScale        44c
+    {UAVXTelemetry,true}, // TelemetryType    45c
+    {8,0},                // MaxDescentRateDmpS     46
+    {30,true},            // DescentDelayS    47c
+    {1,0},                // NavIntLimit        48
+    {2,0},                // AltIntLimit        49
+    {11,true},            // was GravComp        50c
+
+    {0,true},            // was CompSteps    51c
+    {0,true},            // ServoSense        52c    
+    {3,true},            // CompassOffsetQtr 53c
+    {49,true},            // BatteryCapacity    54c    
+    {LY530Gyro,true},    // was GyroYawType    55c        
+    {4,0},                // AltKd            56
+    #if (defined  TRICOPTER) | (defined VTCOPTER )
+    {24,true},                // Orient            57
+    #else    
+    {0,true},                // Orient            57
+    #endif // TRICOPTER | VTCOPTER                
+    
+    {12,true},                // NavYawLimit        58
+    {0,0},                // Balance            59
+    {0,0},                // 60 - 64 unused currently    
+    {0,0},    
+
+    {0,0},    
+    {0,0},    
+    {0,0}                        
+    };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uavx_multicopter.h	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,97 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+   const int8 DefaultParams[MAX_PARAMETERS][2] = {
+    {20,0},            // RollKp,             01
+    {12,0},             // RollKi,            02
+    {50, 0},            // RollKd,            03
+    {0,true},            // HorizDampKp,        04c //-1
+    {5,0},                 // RollIntLimit,    05
+    {20,0},             // PitchKp,            06
+    {12,0},             // PitchKi,            07
+    {50,0},                 // PitchKd,            08
+    {8,0},                 // AltKp,            09
+    {5,0},                 // PitchIntLimit,    10
+    
+    {30,0},             // YawKp,             11
+    {25,0},             // YawKi,            12
+    {0,0},                 // YawKd,            13
+    {25,0},                 // YawLimit,        14
+    {2,0},                 // YawIntLimit,        15
+    {8,true},             // ConfigBits,        16c
+    {0,true},            // was TimeSlots,   17c
+    {48,true},             // LowVoltThres,    18c
+    {20,true},             // CamRollKp,        19c
+    {45,true},             // PercentCruiseThr,20c 
+    
+    {0,true},             // VertDampKp,        21c //-1
+    {0,true},             // MiddleDU,        22c
+    {20,true},             // PercentIdleThr,    23c
+    {0,true},             // MiddleLR,        24c
+    {0,true},             // MiddleFB,        25c
+    {20,true},             // CamPitchKp,        26c
+    {10,0},             // CompassKp,        27
+    {8,0},                // AltKi,            28
+    {0,0},                 // was NavRadius,    29
+    {8,0},                 // NavKi,            30 
+
+    {0,0},                 // GSThrottle,        31
+    {0,0},                // Acro,              32
+    {10,0},                 // NavRTHAlt,        33
+    {0,true},            // NavMagVar,        34c
+    {ITG3200Gyro,true},     // DesGyroType,         35c
+    {ESCPPM,true},         // ESCType,            36c
+    {UnknownTxRx,true},         // TxRxType            37c
+    {2,true},                // NeutralRadius    38
+    {30,true},                // PercentNavSens6Ch    39
+    {1,true},            // CamRollTrim,        40c
+
+    {16,0},            // NavKd            41
+    {1,true},            // VertDampDecay    42c
+    {1,true},            // HorizDampDecay    43c
+    {56,true},            // BaroScale        44c
+    {UAVXTelemetry,true}, // TelemetryType    45c
+    {8,0},                // MaxDescentRateDmpS     46
+    {30,true},            // DescentDelayS    47c
+    {1,0},                // NavIntLimit        48
+    {2,0},                // AltIntLimit        49
+    {11,true},            // was GravComp        50c
+
+    {0,true},            // was CompSteps    51c
+    {0,true},            // ServoSense        52c    
+    {3,true},            // CompassOffsetQtr 53c
+    {49,true},            // BatteryCapacity    54c    
+    {ITG3200Gyro,true},    // was GyroYawType    55c        
+    {4,0},                // AltKd            56
+    #if (defined  TRICOPTER) | (defined VTCOPTER )
+    {24,true},                // Orient            57
+    #else    
+    {0,true},                // Orient            57
+    #endif // TRICOPTER | VTCOPTER                
+    
+    {12,true},                // NavYawLimit        58
+    {0,0},                // Balance            59
+    {0,0},                // 60 - 64 unused currently    
+    {0,0},    
+
+    {0,0},    
+    {0,0},    
+    {0,0}                        
+    };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utils.c	Fri Feb 18 22:28:05 2011 +0000
@@ -0,0 +1,170 @@
+// ===============================================================================================
+// =                              UAVXArm Quadrocopter Controller                                =
+// =                           Copyright (c) 2008 by Prof. Greg Egan                             =
+// =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
+// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// ===============================================================================================
+
+//    This is part of UAVXArm.
+
+//    UAVXArm is free software: 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 3 of the
+//    License, or (at your option) any later version.
+
+//    UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
+//    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+
+//    You should have received a copy of the GNU General Public License along with this program.
+//    If not, see http://www.gnu.org/licenses/
+
+#include "UAVXArm.h"
+
+void InitMisc(void);
+void Delay1mS(int16);
+void Delay100mS(int16);
+void DoBeep100mS(uint8, uint8);
+void DoStartingBeeps(uint8);
+void CheckAlarms(void);
+real32 SlewLimit(real32, real32, real32);
+real32 DecayX(real32, real32);
+void LPFilter(real32*, real32*, real32, real32);
+void Timing(uint8, uint32);
+
+TimingRec Times[(UnknownT+1)];
+
+void InitMisc(void) {
+    int8 i;
+
+    State = Starting;                // For trace preconditions
+
+    for ( i = 0; i <= UnknownT; i++ )
+        Times[i].T = Times[i].Count = 0;
+
+    for ( i = 0; i < FLAG_BYTES ; i++ )
+        F.AllFlags[i] = false;
+
+    F.ParametersValid = F.AcquireNewPosition = F.AllowNavAltitudeHold = true;
+
+#ifdef SIMULATE
+    F.Simulation = true;
+#endif // SIMULATE
+
+    BatteryCharge = 0;
+
+    IdleThrottle = ((10L*OUT_MAXIMUM)/100);
+    InitialThrottle = RC_MAXIMUM;
+    ESCMin = OUT_MINIMUM;
+    ESCMax = OUT_MAXIMUM;
+
+    ALL_LEDS_OFF;
+    LEDRed_ON;
+    Beeper_OFF;
+} // InitMisc
+
+void Delay1mS(int16 d) {
+    static int32 Timeout;
+
+    Timeout = timer.read_us() + ((int32)d * 1000 );
+    while (  timer.read_us() < Timeout ) {};
+
+} // Delay1mS
+
+void Delay100mS(int16 d) {
+    Delay1mS( 100 * d );
+} // Delay100mS
+
+void DoBeep100mS(uint8 t, uint8 d) {
+    Beeper_ON;
+    Delay100mS(t);
+    Beeper_OFF;
+    Delay100mS(d);
+} // DoBeep100mS
+
+void DoStartingBeeps(uint8 b) {
+    uint8 i;
+
+    for ( i = 0; i < b; i++ )
+        DoBeep100mS(2, 8);
+
+    DoBeep100mS(8,0);
+} // DoStartingBeeps
+
+void CheckAlarms(void) {
+
+    static uint16 BeeperOnTime, BeeperOffTime;
+
+    F.BeeperInUse = F.LowBatt || F.LostModel  || (State == Shutdown);
+
+    if ( F.BeeperInUse ) {
+        if ( F.LowBatt ) {
+            BeeperOffTime = 750;
+            BeeperOnTime = 250;
+        } else
+            if ( State == Shutdown ) {
+                BeeperOffTime = 4750;
+                BeeperOnTime = 250;
+            } else
+                if ( F.LostModel ) {
+                    BeeperOffTime = 125;
+                    BeeperOnTime = 125;
+                }
+
+        if ( (mSClock() > mS[BeeperUpdate]) && BEEPER_IS_ON ) {
+            mS[BeeperUpdate] = mSClock() + BeeperOffTime;
+            Beeper_OFF;
+            LEDRed_OFF;
+        } else
+            if ( (mSClock() > mS[BeeperUpdate]) && BEEPER_IS_OFF ) {
+                mS[BeeperUpdate] = mSClock() + BeeperOnTime;
+                Beeper_ON;
+                LEDRed_ON;
+            }
+    }
+#ifdef NAV_ACQUIRE_BEEPER
+    else
+        if ( (State == InFlight) && (!F.AcquireNewPosition) && (mSClock() > mS[BeeperTimeout]) )
+            Beeper_OFF;
+#endif // NAV_ACQUIRE_BEEPER 
+
+} // CheckAlarms
+
+real32 DecayX(real32 i, real32 d) {
+    if ( i < 0 ) {
+        i += d;
+        if ( i >0 )
+            i = 0;
+    } else
+        if ( i > 0 ) {
+            i -= d;
+            if ( i < 0 )
+                i = 0;
+        }
+    return (i);
+} // DecayX
+
+void LPFilter(real32* i, real32* ip, real32 FilterF, real32 dT) {
+    static real32 FilterA;
+
+    FilterA = dT / ( FilterF + dT );
+
+    *i = *ip + (*i - *ip) * FilterA;
+    *ip = *i;
+
+} // LPFilter
+
+real32 SlewLimit(real32 Old, real32 New, real32 Slew) {
+    real32 Low, High;
+
+    Low = Old - Slew;
+    High = Old + Slew;
+    return(( New < Low ) ? Low : (( New > High ) ? High : New));
+} // SlewLimit
+
+void Timing(uint8 w, uint32 T) {
+
+    Times[w].T += timer.read_us() - T;
+    Times[w].Count++;
+
+} // Timing
+