Reaction Wheel Actuated Satellite Dynamics Test Platform

Dependencies:   mbed

Diploma Thesis in Aerospace Engineering, January 2014

University of Applied Sciences Munich, Faculty 03

Electronics:

  • 1x mbed NXP LPC 1768 Microcontroller
  • 2x XBee S1 Radios + Sparkfun USB Adapter
  • 1x CHR UM6-lt IMU
  • 4x Graupner BEC 8 Motor Controllers
  • 4x ROXXY 2826/09 Brushless Motors
  • 1x Hacker TopFuel LiPo 1300mAh Battery
  • 1x big Selfmade BreakOutBoard to connect all components
  • 1x small BreakOutBoard to connect IMU

Hardware developed with Catia V5R20

Manufactoring Technology: Rapid Prototyping - EOS Formiga P110

Controlled via text based menu with DockLight

__________________

Files at this revision

API Documentation at this revision

Comitter:
DimitriGruebel
Date:
Wed Jul 09 07:35:50 2014 +0000
Commit message:
Dynamics Test Platform

Changed in this revision

MODSERIAL/ChangeLog.c Show annotated file Show diff for this revision Revisions of this file
MODSERIAL/FLUSH.cpp Show annotated file Show diff for this revision Revisions of this file
MODSERIAL/GETC.cpp Show annotated file Show diff for this revision Revisions of this file
MODSERIAL/INIT.cpp Show annotated file Show diff for this revision Revisions of this file
MODSERIAL/ISR_RX.cpp Show annotated file Show diff for this revision Revisions of this file
MODSERIAL/ISR_TX.cpp Show annotated file Show diff for this revision Revisions of this file
MODSERIAL/MACROS.h Show annotated file Show diff for this revision Revisions of this file
MODSERIAL/MODSERIAL.cpp Show annotated file Show diff for this revision Revisions of this file
MODSERIAL/MODSERIAL.h Show annotated file Show diff for this revision Revisions of this file
MODSERIAL/MODSERIAL_IRQ_INFO.cpp Show annotated file Show diff for this revision Revisions of this file
MODSERIAL/PUTC.cpp Show annotated file Show diff for this revision Revisions of this file
MODSERIAL/RESIZE.cpp Show annotated file Show diff for this revision Revisions of this file
MODSERIAL/example1.cpp Show annotated file Show diff for this revision Revisions of this file
MODSERIAL/example2.cpp Show annotated file Show diff for this revision Revisions of this file
MODSERIAL/example3a.cpp Show annotated file Show diff for this revision Revisions of this file
MODSERIAL/example3b.cpp Show annotated file Show diff for this revision Revisions of this file
MODSERIAL/example_dma.cpp Show annotated file Show diff for this revision Revisions of this file
UM6_config/UM6_config.h Show annotated file Show diff for this revision Revisions of this file
UM6_usart/UM6_usart.h Show annotated file Show diff for this revision Revisions of this file
main.cpp 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
diff -r 000000000000 -r 1447d2f773db MODSERIAL/ChangeLog.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/ChangeLog.c	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,165 @@
+/* $Id:$
+
+1.23    25th July 2012
+
+    * LPC1768 code as was. This release includes "alpha" support for the LPC11U24
+
+1.22    19th April 2012
+
+    * http://mbed.org/forum/bugs-suggestions/topic/2936/
+    * Bug fix, protect important buffer pointers from IRQ corruption.
+      Credits: 
+        Anthony Wieser  http://mbed.org/users/WieserSoftwareLtd/ for the fix.
+        BlazeX http://mbed.org/users/BlazeX/ for the alert that a fix was needed!
+
+1.21    10 May 2011
+    
+    * http://mbed.org/forum/mbed/topic/2264
+    
+1.20    26 April 2011
+
+    * Bug fix, not blocking on transmit
+      by Erik Petrich, http://mbed.org/forum/bugs-suggestions/topic/2200
+      
+1.19    20 April 2011
+
+    * Fixed some doxygen comment bugs.
+    
+1.18    20 April 2011
+
+    * All callbacks now use MODSERIAL_callback (rather than Mbed's FunctionPointer[1] type)
+      to store and invoke it's callbacks. This allows MODSERIAL to pass a parameter
+      to callbacks. The function prototype is now void func(MODSERIAL_IRQ_INFO *q).
+    * Callbacks now pass a pointer to a MODSERIAL_IRQ_INFO class type.
+      This class holds a pointer to the MODSERIAL object that invoked the callback
+      thus freeing callbacks need to use the global variable of the original 
+      MODSERIAL instance.
+    * MODSERIAL_IRQ_INFO also declares public functions that are protected within MODSERIAL
+      thus allowing certain functions to be restricted to callback context only.
+    * New function MODSERIAL_IRQ_INFO::rxDiscardLastChar() allows an rxCallback function
+      to remove the character that was just placed into the RX buffer.
+    
+    [1] http://mbed.org/users/AjK/libraries/FPointer/latest/docs/
+
+1.17   08/Mar/2011
+       Fixed a memory leak in the DMA code.
+       
+1.16 - 12 Feb 2011
+    
+    * Missed one, doh!
+
+1.15 - 12 Feb 2011
+    
+    * Fixed some typos.
+    
+1.14 - 7 Feb 2011
+
+    * Fixed a bug in __putc() that caused the output buffer pointer to 
+      become corrupted.
+
+1.13 - 20/01/2011
+
+    * Added extra documentation.
+    * Fixed some typos.
+    
+1.12 - 20/01/2011
+
+    * Added new "autoDetectChar()" function. To use:-
+      1st: Add a callback to invoke when the char is detected:-        
+        .attach(&detectedChar, MODSERIAL::RxAutoDetect);
+      2nd: Send the char to detect.
+        .autoDectectChar('\n');
+      Whenever that char goes into the RX buffer your callback will be invoked.
+      Added example2.cpp to demo a simple messaging system using this auto feature.
+
+
+1.11 - 23/11/2010
+
+    * Fixed a minor issue with 1.10 missed an alteration of name change.
+    
+1.10 - 23/11/2010
+
+    * Rename the DMA callback from attach_dma_complete() to attach_dmaSendComplete()
+    
+1.9 - 23/11/2010
+
+    * Added support for DMA sending of characters. Required is
+      the MODDMA library module:-
+      http://mbed.org/users/AjK/libraries/MODDMA/latest
+      See example_dma.cpp for more information.
+      
+1.8 - 22/11/2010
+
+    * Added code so that if a buffer is set to zero length then
+      MODSERIAL defaults to just using the FIFO for that stream
+      thus making the library "fall back" to teh same operation
+      that the Mbed Serial library performs.
+    * Removed dmaSend() function that should have been removed 
+      at 1.7
+    
+1.7 - 21/11/2010
+
+    * Remove the DMA enum from MODSERIAL.h as it's not currently 
+      ready for release.
+    * Added page doxygen comments.
+
+1.6 - 21/11/2010
+
+   * Version 1.5 solved a blocking problem on putc() when called 
+     from another ISR. However, isr_tx() invokes a callback of it's
+     own when a byte is tranferred from TX buffer to TX FIFO. User
+     programs may interpret that as an IRQ callback. That's an ISR
+     call from within an existing ISR which is not good. So the 
+     TxIrq callback from isr_tx is now conditional. It will only
+     be called when isr_tx() is actually within it's own ISR and
+     not when called from alternate ISR handlers.
+     
+1.5 - 21/11/2010
+
+    * Calling putc() (or any derived function that uses it like
+      printf()) while inside an interrupt service routine can
+      cause the system to lock up if the TX buffer is full. This
+      is because bytes are only transferred from the TX buffer to
+      the TX FIFO via the TX ISR. If we are, say in an RX ISR already,
+      then the TX ISR will never trigger. The TX buffer stays full and
+      there is never space to putc() the byte. So, while putc() blocks
+      waiting for space it calls isr_tx() to ensure if TX FIFO space
+      becomes available it will move bytes from the TX buffer to TX
+      FIFO thus removing the blocking condition within putc().
+
+1.4 - 21/11/2010
+
+    * Removed all the new DMA code. I wish mbed.org had proper SVN
+      versioning, I'm use to working in HEAD and BRANCHES after I've
+      released a project. Getting bug reports in current releases
+      while trying to dev new code is hard to manage without source
+      control of some type!
+
+1.3 - 21/11/2010
+
+    * Fixed a macro problem with txIsBusy()
+    * Started adding code to use "block data" sending using DMA
+    * Removed #include "IOMACROS.h"
+    
+1.2 - 21/11/2010
+
+    * Removed unsed variables from flushBuffer()
+    * Fixed a bug where both RX AND TX fifos are cleared/reset 
+      when just TX OR RX should be cleared.
+    * Fixed a bug that cleared IIR when in fact it should be left
+      alone so that any pending interrupt after flush is handled.
+    * Merged setBase() into init() as it wasn't required anywhere else.
+    * Changed init() to enforce _uidx is set by Serial to define the _base
+      address of the Uart in use.
+        
+1.1 - 20/11/2010
+
+    * Added this file
+    * Removed cruft from GETC.cpp
+    * "teh" should be "the", why do my fingers do that?
+
+1.0 - 20/11/2010
+
+    * First release.
+
+*/
\ No newline at end of file
diff -r 000000000000 -r 1447d2f773db MODSERIAL/FLUSH.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/FLUSH.cpp	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,47 @@
+/*
+    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 "MODSERIAL.h"
+#include "MACROS.h"
+
+namespace AjK {
+
+void
+MODSERIAL::flushBuffer(IrqType type)
+{
+    uint32_t ier = _IER;
+    switch(type) {
+        case TxIrq: _IER &= ~(1UL << 1); break;
+        case RxIrq: _IER &= ~(1UL << 0); break;
+    }
+    buffer_in[type]       = 0;
+    buffer_out[type]      = 0;
+    buffer_count[type]    = 0;
+    buffer_overflow[type] = 0;  
+    switch(type) {
+        case TxIrq: _FCR = MODSERIAL_FIFO_TX_RESET; break;
+        case RxIrq: _FCR = MODSERIAL_FIFO_RX_RESET; break;
+    }
+    _IER = ier;
+}
+
+}; // namespace AjK ends
diff -r 000000000000 -r 1447d2f773db MODSERIAL/GETC.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/GETC.cpp	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,65 @@
+/*
+    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 "MODSERIAL.h"
+#include "MACROS.h"
+
+namespace AjK {
+
+int 
+MODSERIAL::__getc(bool block)
+{
+    // If no buffer is in use fall back to standard RX FIFO usage.
+    // Note, we must block in this case and ignore bool "block" 
+    // so as to maintain compat with Mbed Serial.
+    if (buffer_size[RxIrq] == 0 || buffer[RxIrq] == (char *)NULL) {
+        while(! MODSERIAL_RBR_HAS_DATA ) ;
+        return (int)(_RBR & 0xFF);
+    }
+
+    if (block) { while ( MODSERIAL_RX_BUFFER_EMPTY ) ; } // Blocks.
+    else if ( MODSERIAL_RX_BUFFER_EMPTY ) return -1;
+    
+    int c = buffer[RxIrq][buffer_out[RxIrq]];
+    buffer_out[RxIrq]++;
+    if (buffer_out[RxIrq] >= buffer_size[RxIrq]) {
+        buffer_out[RxIrq] = 0;
+    }
+    
+    // If we have made space in the RX Buffer then copy over
+    // any characters in the RX FIFO that my reside there.
+    // Temporarily disable the RX IRQ so that we do not re-enter 
+    // it under interrupts.
+    if ( ! MODSERIAL_RX_BUFFER_FULL ) {
+        uint32_t ier = _IER;
+        _IER &= ~(1UL << 0);
+        isr_rx();    
+        _IER = ier;
+    }
+    
+    __disable_irq();
+    buffer_count[RxIrq]--;   
+    __enable_irq();
+    return c;
+}
+
+}; // namespace AjK ends
diff -r 000000000000 -r 1447d2f773db MODSERIAL/INIT.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/INIT.cpp	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,80 @@
+/*
+    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 "MODSERIAL.h"
+#include "MACROS.h"
+
+namespace AjK {
+
+void
+MODSERIAL::init( int txSize, int rxSize )
+{
+    disableIrq();
+    
+    callbackInfo.setSerial(this);
+
+#ifdef __LPC11UXX_H__
+
+    _base = LPC_USART;
+    
+#else    
+    switch(_serial.index) {
+        case 0:   _base = LPC_UART0; break;
+        case 1:   _base = LPC_UART1; break;
+        case 2:   _base = LPC_UART2; break;
+        case 3:   _base = LPC_UART3; break;
+        default : _base = NULL;      break;
+    }
+#endif
+    
+    dmaSendChannel  = -1;
+    moddma_p        = (void *)NULL;
+    
+    if (_base != NULL) {
+        buffer_size[RxIrq]     = rxSize;
+        buffer[RxIrq]          = rxSize > 0 ? (char *)malloc(buffer_size[RxIrq]) : (char *)NULL;
+        buffer_in[RxIrq]       = 0;
+        buffer_out[RxIrq]      = 0;
+        buffer_count[RxIrq]    = 0;
+        buffer_overflow[RxIrq] = 0;
+        Serial::attach(this, &MODSERIAL::isr_rx, Serial::RxIrq);        
+        
+        buffer_size[TxIrq]     = txSize;
+        buffer[TxIrq]          = txSize > 0 ? (char *)malloc(buffer_size[TxIrq]) : (char *)NULL;
+        buffer_in[TxIrq]       = 0;
+        buffer_out[TxIrq]      = 0;
+        buffer_count[TxIrq]    = 0;
+        buffer_overflow[TxIrq] = 0;
+        Serial::attach(this, &MODSERIAL::isr_tx, Serial::TxIrq);
+    }
+    else {
+        error("MODSERIAL must have a defined UART to function.");
+    }
+    
+    _FCR = MODSERIAL_FIFO_ENABLE | MODSERIAL_FIFO_RX_RESET | MODSERIAL_FIFO_TX_RESET;
+    
+    auto_detect_char = 0;
+    
+    enableIrq();
+}
+
+}; // namespace AjK ends
diff -r 000000000000 -r 1447d2f773db MODSERIAL/ISR_RX.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/ISR_RX.cpp	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,60 @@
+/*
+    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 "MODSERIAL.h"
+#include "MACROS.h"
+
+namespace AjK {
+        
+void 
+MODSERIAL::isr_rx(void)
+{
+    if (! _base || buffer_size[RxIrq] == 0 || buffer[RxIrq] == (char *)NULL) {
+        _isr[RxIrq].call(&this->callbackInfo); 
+        return;
+    } 
+    
+    while( MODSERIAL_RBR_HAS_DATA ) {
+        rxc = (char)(_RBR & 0xFF); 
+        if ( MODSERIAL_RX_BUFFER_FULL ) {
+            buffer_overflow[RxIrq] = rxc; // Oh dear, no room in buffer.
+            _isr[RxOvIrq].call(&this->callbackInfo);
+        }
+        else {
+            if (buffer[RxIrq] != (char *)NULL) {
+                buffer[RxIrq][buffer_in[RxIrq]] = rxc;
+                buffer_count[RxIrq]++; 
+                buffer_in[RxIrq]++;
+                if (buffer_in[RxIrq] >= buffer_size[RxIrq]) {
+                    buffer_in[RxIrq] = 0;
+                }
+            }  
+            _isr[RxIrq].call(&this->callbackInfo); 
+        }
+        if (auto_detect_char == rxc) {
+            _isr[RxAutoDetect].call(&this->callbackInfo);
+        }
+    }    
+}
+
+}; // namespace AjK ends
+
diff -r 000000000000 -r 1447d2f773db MODSERIAL/ISR_TX.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/ISR_TX.cpp	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,54 @@
+/*
+    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 "MODSERIAL.h"
+#include "MACROS.h"
+
+namespace AjK {
+
+void 
+MODSERIAL::isr_tx(bool doCallback)
+{
+    if (! _base || buffer_size[TxIrq] == 0 || buffer[TxIrq] == (char *)NULL) {
+        _isr[TxIrq].call(&this->callbackInfo); 
+        return;
+    }
+    
+    while (! MODSERIAL_TX_BUFFER_EMPTY && MODSERIAL_THR_HAS_SPACE ) {
+        _THR = txc = (uint8_t)(buffer[TxIrq][buffer_out[TxIrq]]);
+        buffer_count[TxIrq]--;   
+        buffer_out[TxIrq]++;
+        if (buffer_out[TxIrq] >= buffer_size[TxIrq]) {
+            buffer_out[TxIrq] = 0;
+        }
+        if (doCallback) _isr[TxIrq].call(&this->callbackInfo);
+    }
+        
+    if ( MODSERIAL_TX_BUFFER_EMPTY ) { 
+        _IER = 1;
+        _isr[TxEmpty].call(&this->callbackInfo);
+    }        
+}
+
+}; // namespace AjK ends
+
+        
diff -r 000000000000 -r 1447d2f773db MODSERIAL/MACROS.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/MACROS.h	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,70 @@
+/*
+    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 MODSERIAL_MACROS_H
+#define MODSERIAL_MACROS_H
+
+#define MODSERIAL_RBR  0x00
+#define MODSERIAL_THR  0x00
+#define MODSERIAL_DLL  0x00
+#define MODSERIAL_IER  0x04
+#define MODSERIAL_DML  0x04
+#define MODSERIAL_IIR  0x08
+#define MODSERIAL_FCR  0x08
+#define MODSERIAL_LCR  0x0C
+#define MODSERIAL_LSR  0x14
+#define MODSERIAL_SCR  0x1C
+#define MODSERIAL_ACR  0x20
+#define MODSERIAL_ICR  0x24
+#define MODSERIAL_FDR  0x28
+#define MODSERIAL_TER  0x30
+
+#define MODSERIAL_LSR_RDR  (1UL << 0)
+#define MODSERIAL_LSR_OE   (1UL << 1)
+#define MODSERIAL_LSR_PE   (1UL << 2)
+#define MODSERIAL_LSR_FE   (1UL << 3)
+#define MODSERIAL_LSR_BR   (1UL << 4)
+#define MODSERIAL_LSR_THRE (1UL << 5)
+#define MODSERIAL_LSR_TEMT (1UL << 6)
+#define MODSERIAL_LSR_RXFE (1UL << 7)
+
+#define MODSERIAL_FIFO_ENABLE   1
+#define MODSERIAL_FIFO_RX_RESET 2
+#define MODSERIAL_FIFO_TX_RESET 4
+
+#define _RBR    *((char *)_base+MODSERIAL_RBR)
+#define _THR    *((char *)_base+MODSERIAL_THR)
+#define _IIR    *((char *)_base+MODSERIAL_IIR)
+#define _IER    *((char *)_base+MODSERIAL_IER)
+#define _LSR    *((char *)_base+MODSERIAL_LSR)
+#define _FCR    *((char *)_base+MODSERIAL_FCR)
+
+#define MODSERIAL_TX_BUFFER_EMPTY (buffer_count[TxIrq]==0)
+#define MODSERIAL_RX_BUFFER_EMPTY (buffer_count[RxIrq]==0)
+#define MODSERIAL_TX_BUFFER_FULL  (buffer_count[TxIrq]==buffer_size[TxIrq])
+#define MODSERIAL_RX_BUFFER_FULL  (buffer_count[RxIrq]==buffer_size[RxIrq])
+
+#define MODSERIAL_THR_HAS_SPACE ((int)_LSR&MODSERIAL_LSR_THRE)
+#define MODSERIAL_TEMT_IS_EMPTY ((int)_LSR&MODSERIAL_LSR_TEMT)
+#define MODSERIAL_RBR_HAS_DATA  ((int)_LSR&MODSERIAL_LSR_RDR)
+
+#endif
diff -r 000000000000 -r 1447d2f773db MODSERIAL/MODSERIAL.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/MODSERIAL.cpp	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,137 @@
+/*
+    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.
+    
+    @file          MODSERIAL.h 
+    @purpose       Extends Serial to provide fully buffered IO
+    @version       1.6
+    @date          Nov 2010
+    @author        Andy Kirkham    
+*/
+
+#include "MODSERIAL.h"
+#include "MACROS.h"
+
+namespace AjK {
+
+MODSERIAL::MODSERIAL( PinName tx, PinName rx, const char *name ) : Serial( tx, rx, name )
+{
+    init( MODSERIAL_DEFAULT_TX_BUFFER_SIZE, MODSERIAL_DEFAULT_RX_BUFFER_SIZE );
+}
+
+MODSERIAL::MODSERIAL( PinName tx, PinName rx, int bufferSize, const char *name ) : Serial( tx, rx, name )
+{
+    init( bufferSize, bufferSize );
+}
+
+MODSERIAL::MODSERIAL( PinName tx, PinName rx, int txSize, int rxSize, const char *name ) : Serial( tx, rx, name )
+{
+    init( txSize, rxSize );
+}
+
+MODSERIAL::~MODSERIAL()
+{
+    disableIrq();
+    if ( buffer[0] != NULL) free((char *)buffer[0] );
+    if ( buffer[1] != NULL) free((char *)buffer[1] );    
+}
+
+bool 
+MODSERIAL::txBufferFull( void ) 
+{ 
+    return MODSERIAL_TX_BUFFER_FULL; 
+}
+
+bool 
+MODSERIAL::rxBufferFull( void ) 
+{ 
+    return MODSERIAL_RX_BUFFER_FULL; 
+}
+
+bool 
+MODSERIAL::txBufferEmpty( void ) 
+{ 
+    return MODSERIAL_TX_BUFFER_EMPTY; 
+}
+
+bool 
+MODSERIAL::rxBufferEmpty( void ) 
+{ 
+    return MODSERIAL_RX_BUFFER_EMPTY; 
+}
+
+bool 
+MODSERIAL::txIsBusy( void ) 
+{ 
+    return ( _LSR & ( 3UL << 5 ) == 0 ) ? true : false; 
+} 
+
+void
+MODSERIAL::disableIrq( void )
+{
+
+#ifdef __LPC11UXX_H__
+    NVIC_DisableIRQ( UART_IRQn );
+#else
+    switch(_serial.index) {
+        case 0:   NVIC_DisableIRQ( UART0_IRQn ); break;
+        case 1:   NVIC_DisableIRQ( UART1_IRQn ); break;
+        case 2:   NVIC_DisableIRQ( UART2_IRQn ); break;
+        case 3:   NVIC_DisableIRQ( UART3_IRQn ); break;
+    }
+#endif
+}
+
+void
+MODSERIAL::enableIrq(void)
+{
+#ifdef __LPC11UXX_H__
+    NVIC_EnableIRQ( UART_IRQn );
+#else
+    switch( _serial.index ) {
+        case 0:   NVIC_EnableIRQ( UART0_IRQn ); break;
+        case 1:   NVIC_EnableIRQ( UART1_IRQn ); break;
+        case 2:   NVIC_EnableIRQ( UART2_IRQn ); break;
+        case 3:   NVIC_EnableIRQ( UART3_IRQn ); break;
+    }
+#endif
+}
+
+int 
+MODSERIAL::rxDiscardLastChar( void )
+{
+    // This function can only be called indirectly from
+    // an rxCallback function. Therefore, we know we 
+    // just placed a char into the buffer.
+    char c = buffer[RxIrq][buffer_in[RxIrq]];
+    
+    if (buffer_count[RxIrq]) {        
+        buffer_count[RxIrq]--;
+        buffer_in[RxIrq]--;
+        if (buffer_in[RxIrq] < 0) {
+            buffer_in[RxIrq] = buffer_size[RxIrq] - 1;
+        }
+    }
+    
+    return (int)c;
+}
+
+
+}; // namespace AjK ends
diff -r 000000000000 -r 1447d2f773db MODSERIAL/MODSERIAL.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/MODSERIAL.h	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,1091 @@
+/*
+    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.
+    
+    @file          MODSERIAL.h 
+    @purpose       Extends Serial to provide fully buffered IO
+    @version       see ChangeLog.c
+    @date          Nov 2010
+    @author        Andy Kirkham
+*/
+
+#ifndef MODSERIAL_H
+#define MODSERIAL_H
+
+/** @defgroup API The MODSERIAL API */
+/** @defgroup MISC Misc MODSERIAL functions */
+/** @defgroup INTERNALS MODSERIAL Internals */
+
+#ifndef MODSERIAL_DEFAULT_RX_BUFFER_SIZE
+#define MODSERIAL_DEFAULT_RX_BUFFER_SIZE    256
+#endif
+
+#ifndef MODSERIAL_DEFAULT_TX_BUFFER_SIZE
+#define MODSERIAL_DEFAULT_TX_BUFFER_SIZE    256
+#endif
+
+#include "mbed.h"
+
+namespace AjK {
+
+// Forward reference.
+class MODSERIAL;
+
+/**
+ * @author Andy Kirkham
+ * @see http://mbed.org/cookbook/MODSERIAL
+ * @see example3a.cpp
+ * @see example3b.cpp
+ * @see API 
+ *
+ * <b>MODSERIAL_IRQ_INFO</b> is a class used to pass information (and access to protected
+ * MODSERIAL functions) to IRQ callbacks. 
+ */
+class MODSERIAL_IRQ_INFO
+{
+public:
+    friend class MODSERIAL;
+    
+    MODSERIAL *serial;
+    
+    MODSERIAL_IRQ_INFO() { serial = 0; }
+    
+    /** rxDiscardLastChar()
+     *
+     * Remove the last char placed into the rx buffer.
+     * This is an operation that can only be performed
+     * by an rxCallback function. 
+     * @ingroup API
+     * @return The byte removed from the buffer.
+     */
+    int rxDiscardLastChar(void);
+
+protected:
+
+    /** setSerial()
+     *
+     * Used internally by MODSERIAL to set the "this" pointer
+     * of the MODSERIAL that created this object.
+     * @ingroup INTERNAL
+     * @param A pointer to a MODSERIAL object instance.
+     */
+    void setSerial(MODSERIAL *s) { serial = s; }    
+};
+
+// Forward reference dummy class.
+class MODSERIAL_callback_dummy;
+
+/**
+ * @author Andy Kirkham
+ * @see http://mbed.org/cookbook/MODSERIAL
+ * @see example3a.cpp
+ * @see example3b.cpp
+ * @see API 
+ *
+ * <b>MODSERIAL_callback</b> is a class used to hold application callbacks that
+ * MODSERIAL can invoke on certain events.
+ */
+class MODSERIAL_callback 
+{
+protected:
+
+    //! C callback function pointer.
+    void (*c_callback)(MODSERIAL_IRQ_INFO *); 
+    
+    //! C++ callback object/method pointer (the object part).
+    MODSERIAL_callback_dummy *obj_callback;
+    
+    //! C++ callback object/method pointer (the method part).
+    void (MODSERIAL_callback_dummy::*method_callback)(MODSERIAL_IRQ_INFO *);
+
+public:
+    
+    /** Constructor
+     */
+    MODSERIAL_callback() {
+        c_callback      = 0;
+        obj_callback    = 0;
+        method_callback = 0;
+    }
+    
+    /** attach - Overloaded attachment function.
+     *
+     * Attach a C type function pointer as the callback.
+     *
+     * Note, the callback function prototype must be:-
+     * @code
+     * void myCallbackFunction(MODSERIAL_IRQ_INFO *);
+     * @endcode
+     * @param A C function pointer to call.
+     */
+    void attach(void (*function)(MODSERIAL_IRQ_INFO *) = 0) { c_callback = function; }
+    
+    /** attach - Overloaded attachment function.
+     *
+     * Attach a C++ type object/method pointer as the callback.
+     *
+     * Note, the callback method prototype must be:-
+     * @code
+     *     public:
+     *         void myCallbackFunction(MODSERIAL_IRQ_INFO *);
+     * @endcode
+     * @param A C++ object pointer.
+     * @param A C++ method within the object to call.
+     */
+    template<class T> 
+    void attach(T* item, void (T::*method)(MODSERIAL_IRQ_INFO *)) { 
+        obj_callback    = (MODSERIAL_callback_dummy *)item; 
+        method_callback = (void (MODSERIAL_callback_dummy::*)(MODSERIAL_IRQ_INFO *))method; 
+    }
+
+    /** call - Overloaded callback initiator.
+     *
+     * call the callback function.
+     *
+     * @param A pointer to a MODSERIAL_IRQ_INFO object.
+     */
+    void call(MODSERIAL_IRQ_INFO *arg) {
+        if (c_callback != 0) {
+            (*c_callback)(arg);
+        }
+        else {
+            if (obj_callback  != 0 && method_callback != 0) {
+                (obj_callback->*method_callback)(arg);
+            }
+        }       
+    }    
+};
+
+/**
+ * @author Andy Kirkham
+ * @see http://mbed.org/cookbook/MODSERIAL
+ * @see http://mbed.org/handbook/Serial
+ * @see example1.cpp
+ * @see example2.cpp
+ * @see example3a.cpp
+ * @see example3b.cpp
+ * @see example_dma.cpp
+ * @see API 
+ *
+ * <b>MODSERIAL</b> extends the Mbed library <a href="/handbook/Serial">Serial</a> to provide fully buffered
+ * TX and RX streams. Buffer length is fully customisable. 
+ *
+ * Before using MODSERIAL users should be familar with Mbed's standard <a href="/handbook/Serial">Serial</a>
+ * library object. MODSERIAL is a direct "drop in" replacement for <a href="/handbook/Serial">Serial</a>. Where
+ * previously Serial was used, MODSERIAL can be used as adirect replacement instantly offering standard
+ * TX and RX buffering. By default, both TX and RX buffers are 256 bytes in length.
+ *
+ * @image html /media/uploads/mbedofficial/serial_interfaces.png
+ *
+ * Standard example:
+ * @code
+ * #include "mbed.h"
+ * #include "MODSERIAL.h"
+ *
+ * MODSERIAL pc(USBTX, USBRX); // tx, rx
+ *
+ * int main() {
+ *     pc.printf("Hello World!");
+ *     while(1) {
+ *         pc.putc(pc.getc() + 1);
+ *     }
+ * }
+ * @endcode
+ *
+ * Example with alternate buffer length:
+ * @code
+ * #include "mbed.h"
+ * #include "MODSERIAL.h"
+ *
+ * // Make TX and RX buffers 512byes in length
+ * MODSERIAL pc(USBTX, USBRX, 512); // tx, rx
+ *
+ * int main() {
+ *     pc.printf("Hello World!");
+ *     while(1) {
+ *         pc.putc(pc.getc() + 1);
+ *     }
+ * }
+ * @endcode
+ *
+ * Example with alternate buffer length:
+ * @code
+ * #include "mbed.h"
+ * #include "MODSERIAL.h"
+ *
+ * // Make TX 1024bytes and RX 512byes in length
+ * MODSERIAL pc(USBTX, USBRX, 1024, 512); // tx, rx
+ *
+ * int main() {
+ *     pc.printf("Hello World!");
+ *     while(1) {
+ *         pc.putc(pc.getc() + 1);
+ *     }
+ * }
+ * @endcode
+ */
+class MODSERIAL : public Serial 
+{
+public:
+
+    // Allow instances of MODSERIAL_IRQ_INFO to use protected properties and methods.
+    friend class MODSERIAL_IRQ_INFO;
+
+    //! A copy of the Serial parity enum
+    /** @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.format */
+    enum Parity {
+          None = 0
+        , Odd
+        , Even
+        , Forced1   
+        , Forced0
+    };
+    
+    //! A copy of the Serial IrqType enum
+    enum IrqType {
+          RxIrq = 0
+        , TxIrq
+        , RxOvIrq
+        , TxOvIrq
+        , TxEmpty
+        , RxAutoDetect
+        , NumOfIrqTypes
+    };
+    
+    //! Non-blocking functions return code.
+    enum Result {
+          Ok = 0                /*!< Ok. */
+        , NoMemory       = -1   /*!< Memory allocation failed. */
+        , NoChar         = -1   /*!< No character in buffer. */
+        , BufferOversize = -2   /*!< Oversized buffer. */
+    };
+    
+    /**
+     * The MODSERIAL constructor is used to initialise the serial object.
+     *
+     * @param tx PinName of the TX pin.
+     * @param rx PinName of the TX pin.
+     * @param name An option name for RPC usage.
+     */    
+    MODSERIAL(PinName tx, PinName rx, const char *name = NULL);
+    
+    /**
+     * The MODSERIAL constructor is used to initialise the serial object.
+     *
+     * @param tx PinName of the TX pin.
+     * @param rx PinName of the TX pin.
+     * @param bufferSize Integer of the TX and RX buffer sizes.
+     * @param name An option name for RPC usage.
+     */    
+    MODSERIAL(PinName tx, PinName rx, int bufferSize, const char *name = NULL);
+    
+    /**
+     * The MODSERIAL constructor is used to initialise the serial object.
+     *
+     * @param tx PinName of the TX pin.
+     * @param rx PinName of the TX pin.
+     * @param txBufferSize Integer of the TX buffer sizes.
+     * @param rxBufferSize Integer of the RX buffer sizes.
+     * @param name An option name for RPC usage.
+     */    
+    MODSERIAL(PinName tx, PinName rx, int txBufferSize, int rxBufferSize, const char *name = NULL);
+    
+    virtual ~MODSERIAL();
+
+    /**
+     * Function: attach
+     *  
+     * The Mbed standard <a href="/handbook/Serial">Serial</a> library object allows an interrupt callback
+     * to be made when a byte is received by the TX or RX UART hardware. MODSERIAL traps these interrupts
+     * to enable it's buffering system. However, after the byte has been received/sent under interrupt control, 
+     * MODSERIAL can callback a user function as a notification of the interrupt. Note, user code should not
+     * directly interact with the Uart hardware, MODSERIAL does that, instead, MODSERIAL API functions should
+     * be used.
+     *
+     * <b>Note</b>, a character is written out then, if there is room in the TX FIFO and the TX buffer is empty,
+     * putc() will put the character directly into THR (the output holding register). If the TX FIFO is full and 
+     * cannot accept the character, it is placed into the TX output buffer. The TX interrupts are then enabled
+     * so that when the TX FIFO empties, the TX buffer is then transferred to the THR FIFO. The TxIrq will ONLY 
+     * be activated when this transfer of a character from BUFFER to THR FIFO takes place. If your character 
+     * throughput is not high bandwidth, then the 16 byte TX FIFO may be enough and the TX output buffer may 
+     * never come into play.
+     *
+     * @code
+     * #include "mbed.h"
+     * #include "MODSERIAL.h"
+     *
+     * DigitalOut led1(LED1);
+     * DigitalOut led2(LED2);
+     * DigitalOut led3(LED3);
+     *
+     * // To test, connect p9 to p10 as a loopback.
+     * MODSERIAL pc(p9, p10);
+     *
+     * // This function is called when a character goes into the TX buffer.
+     * void txCallback(void) {
+     *     led2 = !led2;
+     * }
+     *
+     * // This function is called when a character goes into the RX buffer.
+     * void rxCallback(void) {
+     *     led3 = !led3;
+     * }
+     *
+     * int main() {
+     *     pc.baud(115200);
+     *     pc.attach(&txCallback, MODSERIAL::TxIrq);
+     *     pc.attach(&rxCallback, MODSERIAL::RxIrq);
+     *
+     *     while(1) {
+     *         led1 = !led1;
+     *         wait(0.5);
+     *         pc.putc('A');
+     *         wait(0.5);
+     *     }
+     * ]
+     * @endcode
+     *
+     * @ingroup API
+     * @param fptr A pointer to a void function, or 0 to set as none
+     * @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
+     */  
+    void attach(void (*fptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) { _isr[type].attach(fptr); }
+    
+    /**
+     * Function: attach
+     *  
+     * The Mbed standard <a href="/handbook/Serial">Serial</a> library object allows an interrupt callback
+     * to be made when a byte is received by the TX or RX UART hardware. MODSERIAL traps these interrupts
+     * to enable it's buffering system. However, after the byte has been received/sent under interrupt control, 
+     * MODSERIAL can callback a user function as a notification of the interrupt. Note, user code should not
+     * directly interact with the Uart hardware, MODSERIAL does that, instead, MODSERIAL API functions should
+     * be used.
+     *
+     * <b>Note</b>, a character is written out then, if there is room in the TX FIFO and the TX buffer is empty,
+     * putc() will put the character directly into THR (the output holding register). If the TX FIFO is full and 
+     * cannot accept the character, it is placed into the TX output buffer. The TX interrupts are then enabled
+     * so that when the TX FIFO empties, the TX buffer is then transferred to the THR FIFO. The TxIrq will ONLY 
+     * be activated when this transfer of a character from BUFFER to THR FIFO takes place. If your character 
+     * throughput is not high bandwidth, then the 16 byte TX FIFO may be enough and the TX output buffer may 
+     * never come into play.
+     *
+     * @code
+     * #include "mbed.h"
+     * #include "MODSERIAL.h"
+     *
+     * DigitalOut led1(LED1);
+     * DigitalOut led2(LED2);
+     * DigitalOut led3(LED3);
+     *
+     * // To test, connect p9 to p10 as a loopback.
+     * MODSERIAL pc(p9, p10);
+     *
+     * class Foo {
+     * public:
+     *     // This method is called when a character goes into the TX buffer.
+     *     void txCallback(void) { led2 = !led2; }
+     *
+     *     // This method is called when a character goes into the RX buffer.
+     *     void rxCallback(void) { led3 = !led3; }
+     * };
+     *
+     * Foo foo;
+     *
+     * int main() {
+     *     pc.baud(115200);
+     *     pc.attach(&foo, &Foo::txCallback, MODSERIAL::TxIrq);
+     *     pc.attach(&foo, &Foo::rxCallback, MODSERIAL::RxIrq);
+     *
+     *     while(1) {
+     *         led1 = !led1;
+     *         wait(0.5);
+     *         pc.putc('A');
+     *         wait(0.5);
+     *     }
+     * ]
+     * @endcode
+     *     
+     * @ingroup API
+     * @param  tptr A pointer to the object to call the member function on
+     * @param  mptr A pointer to the member function to be called
+     * @param  type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
+     */
+    template<typename T>
+    void attach(T* tptr, void (T::*mptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) {
+        if((mptr != 0) && (tptr != 0)) {
+            _isr[type].attach(tptr, mptr);            
+        }
+    }
+
+    /**
+     * @see attach
+     * @ingroup API
+     */
+    void connect(void (*fptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) { _isr[RxIrq].attach(fptr); }
+    
+    /**
+     * @see attach
+     * @ingroup API
+     */
+    template<typename T>
+    void connect(T* tptr, void (T::*mptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) {
+        if((mptr != 0) && (tptr != 0)) {
+            _isr[type].attach(tptr, mptr);            
+        }
+    }
+    
+    /**
+     * Function: writeable
+     *  
+     * Determine if there is space available to write a byte
+     *
+     * @ingroup API
+     * @return 1 if there is space to write a character, else 0
+     */
+    int writeable() { return txBufferFull() ? 0 : 1; }
+    
+    /**
+     * Function: readable
+     *  
+     * Determine if there is a byte available to read
+     *
+     * @ingroup API
+     * @return 1 if there is a character available to read, else 0
+     */
+    int readable() { return rxBufferEmpty() ? 0 : 1; } 
+    
+    /**
+     * Function: txBufferSane
+     *  
+     * Determine if the TX buffer has been initialized.
+     *
+     * @ingroup API
+     * @return true if the buffer is initialized, else false
+     */
+    bool txBufferSane(void) { return buffer[TxIrq] != (char *)NULL ? true : false; }
+    
+    /**
+     * Function: rxBufferSane
+     *  
+     * Determine if the RX buffer has been initialized.
+     *
+     * @ingroup API
+     * @return true if the buffer is initialized, else false
+     */
+    bool rxBufferSane(void) { return buffer[TxIrq] != (char *)NULL ? true : false; }
+    
+    /**
+     * Function: txBufferGetCount
+     *  
+     * Returns how many bytes are in the TX buffer
+     *
+     * @ingroup API
+     * @return The number of bytes in the TX buffer
+     */
+    int txBufferGetCount(void)    { return buffer_count[TxIrq]; }
+    
+    /**
+     * Function: rxBufferGetCount
+     *  
+     * Returns how many bytes are in the RX buffer
+     *
+     * @ingroup API
+     * @return The number of bytes in the RX buffer
+     */
+    int rxBufferGetCount(void)    { return buffer_count[RxIrq]; }
+    
+    /**
+     * Function: txBufferGetSize
+     *  
+     * Returns the current size of the TX buffer
+     *
+     * @ingroup API
+     * @return The length iof the TX buffer in bytes
+     */
+    int txBufferGetSize(int size) { return buffer_size[TxIrq]; } 
+    
+    /**
+     * Function: rxBufferGetSize
+     *  
+     * Returns the current size of the RX buffer
+     *
+     * @ingroup API
+     * @return The length iof the RX buffer in bytes
+     */
+    int rxBufferGetSize(int size) { return buffer_size[RxIrq]; } 
+    
+    /**
+     * Function: txBufferFull
+     *  
+     * Is the TX buffer full?
+     *
+     * @ingroup API
+     * @return true if the TX buffer is full, otherwise false
+     */
+    bool txBufferFull(void);
+    
+    /**
+     * Function: rxBufferFull
+     *  
+     * Is the RX buffer full?
+     *
+     * @ingroup API
+     * @return true if the RX buffer is full, otherwise false
+     */
+    bool rxBufferFull(void);
+    
+    /**
+     * Function: txBufferEmpty
+     *  
+     * Is the TX buffer empty?
+     *
+     * @ingroup API
+     * @return true if the TX buffer is empty, otherwise false
+     */
+    bool txBufferEmpty(void);
+    
+    /**
+     * Function: rxBufferEmpty
+     *  
+     * Is the RX buffer empty?
+     *
+     * @ingroup API
+     * @return true if the RX buffer is empty, otherwise false
+     */
+    bool rxBufferEmpty(void);
+    
+    /**
+     * Function: txBufferSetSize
+     *  
+     * Change the TX buffer size.
+     *
+     * @see Result
+     * @ingroup API
+     * @param size The new TX buffer size in bytes.
+     * @param m Perform a memory sanity check. Errs the Mbed if memory alloc fails.
+     * @return Result Ok on success.
+     */
+    int txBufferSetSize(int size, bool m) { return resizeBuffer(size, TxIrq, m); } 
+    
+    /**
+     * Function: rxBufferSetSize
+     *  
+     * Change the RX buffer size.
+     *
+     * @see Result
+     * @ingroup API
+     * @param size The new RX buffer size in bytes.
+     * @param m Perform a memory sanity check. Errs the Mbed if memory alloc fails.
+     * @return Result Ok on success.
+     */
+    int rxBufferSetSize(int size, bool m) { return resizeBuffer(size, RxIrq, m); } 
+    
+    /**
+     * Function: txBufferSetSize
+     *  
+     * Change the TX buffer size.
+     * Always performs a memory sanity check, halting the Mbed on failure.
+     *
+     * @see Result
+     * @ingroup API
+     * @param size The new TX buffer size in bytes.
+     * @return Result Ok on success.
+     */
+    int txBufferSetSize(int size) { return resizeBuffer(size, TxIrq, true); } 
+    
+    /**
+     * Function: rxBufferSetSize
+     *  
+     * Change the RX buffer size.
+     * Always performs a memory sanity check, halting the Mbed on failure.
+     *
+     * @see Result
+     * @ingroup API
+     * @param size The new RX buffer size in bytes.
+     * @return Result Ok on success.
+     */
+    int rxBufferSetSize(int size) { return resizeBuffer(size, RxIrq, true); } 
+    
+    /**
+     * Function: txBufferFlush
+     *  
+     * Remove all bytes from the TX buffer.
+     * @ingroup API
+     */
+    void txBufferFlush(void) { flushBuffer(TxIrq); }
+    
+    /**
+     * Function: rxBufferFlush
+     *  
+     * Remove all bytes from the RX buffer.
+     * @ingroup API
+     */
+    void rxBufferFlush(void) { flushBuffer(RxIrq); }
+        
+    /**
+     * Function: getcNb
+     *
+     * Like getc() but is non-blocking. If no bytes are in the RX buffer this
+     * function returns Result::NoChar (-1)
+     *
+     * @ingroup API
+     * @return A byte from the RX buffer or Result::NoChar (-1) if bufer empty.
+     */
+    int getcNb() { return __getc(false); }
+    
+    /**
+     * Function: getc
+     *
+     * Overloaded version of Serial::getc()
+     * 
+     * This function blocks (if the RX buffer is empty the function will wait for a
+     * character to arrive and then return that character).
+     *
+     * @ingroup API
+     * @return A byte from the RX buffer
+     */
+    int getc()   { return __getc(true);  }
+    
+    /**
+     * Function: txGetLastChar
+     *
+     * Rteurn the last byte to pass through the TX interrupt handler.
+     *
+     * @ingroup MISC
+     * @return The byte
+     */
+    char txGetLastChar(void) { return txc; }
+    
+    /**
+     * Function: rxGetLastChar
+     *
+     * Return the last byte to pass through the RX interrupt handler.
+     *
+     * @ingroup MISC
+     * @return The byte
+     */
+    char rxGetLastChar(void) { return rxc; }
+    
+    /**
+     * Function: txIsBusy
+     *
+     * If the Uart is still actively sending characters this
+     * function will return true.
+     *
+     * @ingroup API
+     * @return bool
+     */
+    bool txIsBusy(void);
+    
+    /**
+     * Function: autoDetectChar
+     *
+     * Set the char that, if seen incoming, invokes the AutoDetectChar callback.
+     *
+     * @ingroup API
+     * @param int c The character to detect.
+     */
+    void autoDetectChar(char c) { auto_detect_char = c; }
+    
+    /**
+     * Function: move
+     *
+     * Move contents of RX buffer to external buffer. Stops if "end" detected.
+     *
+     * @ingroup API
+     * @param char *s The destination buffer address
+     * @param int max The maximum number of chars to move.
+     * @param char end If this char is detected stop moving.
+     */
+    int move(char *s, int max, char end) {
+        int counter = 0;
+        char c;
+        while(readable()) {
+            c = getc();
+            if (c == end) break;
+            *(s++) = c;
+            counter++;
+            if (counter == max) break;
+        }
+        return counter;
+    }
+    
+    /**
+     * Function: move (overloaded)
+     *
+     * Move contents of RX buffer to external buffer. Stops if auto_detect_char detected.
+     *
+     * @ingroup API
+     * @param int max The maximum number of chars to move.
+     * @param char *s The destination buffer address
+     */
+    int move(char *s, int max) {
+        return move(s, max, auto_detect_char);
+    }
+    
+    #if 0 // Inhereted from Serial/Stream, for documentation only
+    /**
+     * Function: putc
+     * 
+     * Write a character
+     * Inhereted from Serial/Stream
+     *
+     * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.putc
+     * @ingroup API
+     * @param c The character to write to the serial port
+     */
+    int putc(int c);
+    #endif
+    
+    #if 0 // Inhereted from Serial/Stream, for documentation only
+    /**
+     * Function: printf
+     *  
+     * Write a formated string
+     * Inhereted from Serial/Stream
+     *
+     * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.printf
+     * @ingroup API
+     * @param format A printf-style format string, followed by the variables to use in formating the string.
+     */
+    int printf(const char* format, ...);
+    #endif
+    
+    #if 0 // Inhereted from Serial/Stream, for documentation only
+    /**
+     * Function: scanf
+     *  
+     * Read a formated string
+     * Inhereted from Serial/Stream
+     *
+     * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.scanf
+     * @ingroup API
+     * @param format - A scanf-style format string, followed by the pointers to variables to store the results.
+     */
+    int scanf(const char* format, ...);
+    #endif
+
+protected:    
+    /**
+     * Used to pass information to callbacks.
+     * @ingroup INTERNALS
+     */
+    MODSERIAL_IRQ_INFO callbackInfo;
+
+    /**
+     * Remove the last char placed into the rx buffer.
+     * This is an operation that can only be performed
+     * by an rxCallback function. To protect the buffers
+     * this function is defined protected so that a 
+     * regular application cannot call it directly. It 
+     * can only be called by the public version within a
+     * MODSERIAL_IRQ_INFO class.
+     * @ingroup INTERNALS
+     * @return The byte removed from the buffer.
+     */
+    int rxDiscardLastChar(void);    
+            
+private:
+
+    /**
+     * A pointer to the UART peripheral base address being used.
+     * @ingroup INTERNALS
+     */
+    void *_base;
+    
+    /**
+     * The last byte to pass through the TX IRQ handler.
+     * @ingroup INTERNALS
+     */
+    volatile char txc;
+    
+    /**
+     * The last byte to pass through the RX IRQ handler.
+     * @ingroup INTERNALS
+     */
+    volatile char rxc;
+    
+    /**
+     * Pointers to the TX and RX buffers.
+     * @ingroup INTERNALS
+     */
+    volatile char *buffer[2];
+    
+    /**
+     * Buffer in pointers.
+     * @ingroup INTERNALS
+     */
+    volatile int   buffer_in[2];
+    
+    /**
+     * Buffer out pointers.
+     * @ingroup INTERNALS
+     */
+    volatile int   buffer_out[2];
+    
+    /**
+     * Buffer lengths.
+     * @ingroup INTERNALS
+     */
+    volatile int   buffer_size[2];
+    
+    /**
+     * Buffer content counters.
+     * @ingroup INTERNALS
+     */
+    volatile int   buffer_count[2];
+    
+    /**
+     * Buffer overflow.
+     * @ingroup INTERNALS
+     */
+    volatile int   buffer_overflow[2];
+    
+    /**
+     * Auto-detect character.
+     * @ingroup INTERNALS
+     */
+    volatile char auto_detect_char;
+    
+    /**
+     * Callback system.
+     * @ingroup INTERNALS
+     */
+    MODSERIAL_callback _isr[NumOfIrqTypes];
+    
+    /**
+     * TX Interrupt Service Routine.
+     * @ingroup INTERNALS
+     */
+    void isr_tx(bool doCallback);
+    
+    /**
+     * TX Interrupt Service Routine stub version.
+     * @ingroup INTERNALS
+     */ 
+    void isr_tx(void) { isr_tx(true); }
+    
+    
+    /**
+     * RX Interrupt Service Routine.
+     * @ingroup INTERNALS
+     */
+    void isr_rx(void);
+    
+    /**
+     * Disable the interrupts for this Uart.
+     * @ingroup INTERNALS
+     */
+    void disableIrq(void);
+    
+    /**
+     * Enable the interrupts for this Uart.
+     * @ingroup INTERNALS
+     */
+    void enableIrq(void);
+    
+    /**
+     * Get a character from the RX buffer
+     * @ingroup INTERNALS
+     * @param bool True to block (wait for input)
+     * @return A byte from the buffer.
+     */
+    int __getc(bool);
+    
+    /**
+     * Put a character from the TX buffer
+     * @ingroup INTERNALS
+     * @param bool True to block (wait for space in the TX buffer if full)
+     * @return 0 on success
+     */
+    int __putc(int c, bool);
+    
+    /**
+     * Function: _putc 
+     * Overloaded virtual function.
+     */
+    virtual int _putc(int c) { return __putc(c, true); }
+    
+    /**
+     * Function: _getc 
+     * Overloaded virtual function.
+     */
+    virtual int _getc()      { return __getc(true); }
+        
+    /** 
+     * Function: init
+     * Initialize the MODSERIAL object
+     * @ingroup INTERNALS
+     */
+    void init(int txSize, int rxSize);
+    
+    /** 
+     * Function: flushBuffer
+     * @ingroup INTERNALS
+     */
+    void flushBuffer(IrqType type);
+
+    /** 
+     * Function: resizeBuffer
+     * @ingroup INTERNALS
+     */
+    int resizeBuffer(int size, IrqType type = RxIrq, bool memory_check = true);   
+    
+    /** 
+     * Function: downSizeBuffer
+     * @ingroup INTERNALS
+     */
+    int downSizeBuffer(int size, IrqType type, bool memory_check); 
+    
+    /** 
+     * Function: upSizeBuffer
+     * @ingroup INTERNALS
+     */
+    int upSizeBuffer(int size, IrqType type, bool memory_check); 
+
+    /*
+     * If MODDMA is available the compile in code to handle sending
+     * an arbitary char buffer. Note, the parts before teh #ifdef
+     * are declared so that MODSERIAL can access then even if MODDMA
+     * isn't avaiable. Since MODDMA.h is only available at this point
+     * all DMA functionality must be declared inline in the class
+     * definition.
+     */
+public:
+
+    int dmaSendChannel;
+    void *moddma_p;
+    
+#ifdef MODDMA_H
+
+    MODDMA_Config *config;
+    
+    /**
+     * Set the "void pointer" moddma_p to be a pointer to a
+     * MODDMA controller class instance. Used to manage the
+     * data transfer of DMA configurations.
+     *
+     * @ingroup API
+     * @param p A pointer to "the" instance of MODDMA.
+     */
+    void MODDMA(MODDMA *p) { moddma_p = p; }
+    
+    /**
+     * Send a char buffer to the Uarts TX system
+     * using DMA. This blocks regular library
+     * sending.
+     *
+     * @param buffer A char buffer of bytes to send.
+     * @param len The length of the buffer to send.
+     * @param dmaChannel The DMA channel to use, defaults to 7
+     * @return MODDMA::Status MODDMA::ok if all went ok
+     */   
+    int dmaSend(char *buffer, int len, int dmaChannel = 7) 
+    {
+        if (moddma_p == (void *)NULL) return -2;
+        class MODDMA *dma = (class MODDMA *)moddma_p;
+        
+        dmaSendChannel = dmaChannel & 0x7;
+        
+        uint32_t conn = MODDMA::UART0_Tx;
+        switch(_serial.index) {
+            case 0: conn = MODDMA::UART0_Tx; break;
+            case 1: conn = MODDMA::UART1_Tx; break;
+            case 2: conn = MODDMA::UART2_Tx; break;
+            case 3: conn = MODDMA::UART3_Tx; break;
+        }
+        
+        config = new MODDMA_Config;
+        config
+         ->channelNum    ( (MODDMA::CHANNELS)(dmaSendChannel & 0x7) )
+         ->srcMemAddr    ( (uint32_t) buffer )
+         ->transferSize  ( len )
+         ->transferType  ( MODDMA::m2p )
+         ->dstConn       ( conn )
+         ->attach_tc     ( this, &MODSERIAL::dmaSendCallback )
+         ->attach_err    ( this, &MODSERIAL::dmaSendCallback )
+        ; // config end
+        
+        // Setup the configuration.
+        if (dma->Setup(config) == 0) { 
+            return -1;
+        }
+        
+        //dma.Enable( MODDMA::Channel_0 );
+        dma->Enable( config->channelNum() );
+        return MODDMA::Ok;
+    }
+    
+    /**
+     * Attach a callback to the DMA completion.
+     *
+     * @ingroup API
+     * @param fptr A function pointer to call
+     * @return this
+     */
+    void attach_dmaSendComplete(void (*fptr)(MODSERIAL_IRQ_INFO *)) {  
+        _isrDmaSendComplete.attach(fptr);         
+    }
+    
+    /**
+     * Attach a callback to the DMA completion.
+     *
+     * @ingroup API
+     * @param tptr A template pointer to the calling object
+     * @param mptr A method pointer within the object to call.
+     * @return this
+     */
+    template<typename T>
+    void attach_dmaSendComplete(T* tptr, void (T::*mptr)(MODSERIAL_IRQ_INFO *)) {  
+        if((mptr != NULL) && (tptr != NULL)) {
+            _isrDmaSendComplete.attach(tptr, mptr);         
+        }
+    }
+    
+    MODSERIAL_callback _isrDmaSendComplete;
+    
+protected:    
+    /**
+     * Callback for dmaSend(). 
+     */
+    void dmaSendCallback(void) 
+    {
+        if (moddma_p == (void *)NULL) return;
+        class MODDMA *dma = (class MODDMA *)moddma_p;
+        
+        MODDMA_Config *config = dma->getConfig();
+        dma->haltAndWaitChannelComplete( (MODDMA::CHANNELS)config->channelNum());
+        dma->Disable( (MODDMA::CHANNELS)config->channelNum() );
+        if (dma->irqType() == MODDMA::TcIrq)  dma->clearTcIrq();
+        if (dma->irqType() == MODDMA::ErrIrq) dma->clearErrIrq();
+        dmaSendChannel = -1;
+        _isrDmaSendComplete.call(&this->callbackInfo);
+        delete(config);
+    }
+    
+#endif // MODDMA_H
+
+};
+
+}; // namespace AjK ends
+
+using namespace AjK;
+
+#endif
diff -r 000000000000 -r 1447d2f773db MODSERIAL/MODSERIAL_IRQ_INFO.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/MODSERIAL_IRQ_INFO.cpp	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,38 @@
+/*
+    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.
+    
+    @file          MODSERIAL_IRQ_INFO.cpp 
+    @author        Andy Kirkham    
+*/
+
+#include "MODSERIAL.h"
+
+namespace AjK {
+
+int 
+MODSERIAL_IRQ_INFO::rxDiscardLastChar(void) 
+{ 
+    if (!serial) return -1;
+    
+    return serial->rxDiscardLastChar(); 
+}
+
+}; // namespace AjK ends
diff -r 000000000000 -r 1447d2f773db MODSERIAL/PUTC.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/PUTC.cpp	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,81 @@
+/*
+    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 "MODSERIAL.h"
+#include "MACROS.h"
+
+namespace AjK {
+
+int
+MODSERIAL::__putc(int c, bool block) {
+    
+    // If no buffer is in use fall back to standard TX FIFO usage.
+    // Note, we must block in this case and ignore bool "block" 
+    // so as to maintain compat with Mbed Serial.
+    if (buffer[TxIrq] == (char *)NULL || buffer_size[TxIrq] == 0) {
+        while (! MODSERIAL_THR_HAS_SPACE) ; // Wait for space in the TX FIFO.
+        _THR = (uint32_t)c;
+        return 0;
+    }
+    
+    if ( MODSERIAL_THR_HAS_SPACE && MODSERIAL_TX_BUFFER_EMPTY && dmaSendChannel == -1 ) {
+        _THR = (uint32_t)c;
+    }
+    else {
+        if (block) {
+            uint32_t ier = _IER; _IER = 1;
+            while ( MODSERIAL_TX_BUFFER_FULL ) {  // Blocks!
+                // If putc() is called from an ISR then we are stuffed
+                // because in an ISR no bytes from the TX buffer will 
+                // get transferred to teh TX FIFOs while we block here.
+                // So, to work around this, instead of sitting in a 
+                // loop waiting for space in the TX buffer (which will
+                // never happen in IRQ context), check to see if the
+                // TX FIFO has space available to move bytes from the
+                // TX buffer to TX FIFO to make space. The easiest way
+                // to do this is to poll the isr_tx() function while we
+                // are blocking.
+                isr_tx(false);
+            }
+            _IER = ier;
+        }
+        else if( MODSERIAL_TX_BUFFER_FULL ) {
+            buffer_overflow[TxIrq] = c; // Oh dear, no room in buffer.
+            _isr[TxOvIrq].call(&this->callbackInfo);
+            return -1;
+        }
+        _IER &= ~2;
+        buffer[TxIrq][buffer_in[TxIrq]] = c;
+        __disable_irq();
+        buffer_count[TxIrq]++;
+        __enable_irq();
+        buffer_in[TxIrq]++;
+        if (buffer_in[TxIrq] >= buffer_size[TxIrq]) {
+            buffer_in[TxIrq] = 0;
+        }            
+        _IER |= 2;        
+    }
+      
+    return 0;
+}
+
+}; // namespace AjK ends
diff -r 000000000000 -r 1447d2f773db MODSERIAL/RESIZE.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/RESIZE.cpp	Wed Jul 09 07:35:50 2014 +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 "MODSERIAL.h"
+#include "MACROS.h"
+
+namespace AjK {
+
+int
+MODSERIAL::resizeBuffer(int size, IrqType type, bool memory_check)
+{
+    int rval = Ok;
+    
+    // If the requested size is the same as the current size there's nothing to do,
+    // just continue to use the same buffer as it's fine as it is.
+    if (buffer_size[type] == size) return rval;
+    
+    // Make sure the ISR cannot use the buffers while we are manipulating them.
+    disableIrq();
+    
+    // If the requested buffer size is larger than the current size, 
+    // attempt to create a new buffer and use it.
+    if (buffer_size[type] < size) {
+        rval = upSizeBuffer(size, type, memory_check);
+    }
+    else if (buffer_size[type] > size) {
+        rval = downSizeBuffer(size, type, memory_check);
+    }
+    
+    // Start the ISR system again with the new buffers.
+    enableIrq();
+    
+    return rval;
+}
+
+int 
+MODSERIAL::downSizeBuffer(int size, IrqType type, bool memory_check)
+{
+    if (size >= buffer_count[type]) {
+        return BufferOversize;
+    }
+    
+    char *s = (char *)malloc(size);
+    
+    if (s == (char *)NULL) {
+        if (memory_check) {
+            error("Failed to allocate memory for %s buffer", type == TxIrq ? "TX" : "RX");
+        }
+        return NoMemory;
+    }
+    
+    int c, new_in = 0;
+    
+    do {
+        c = __getc(false);
+        if (c != -1) s[new_in++] = (char)c;
+        if (new_in >= size) new_in = 0;
+    }
+    while (c != -1);
+    
+    free((char *)buffer[type]);
+    buffer[type]      = s;
+    buffer_in[type]   = new_in;
+    buffer_out[type]  = 0;
+    return Ok;        
+}
+
+int 
+MODSERIAL::upSizeBuffer(int size, IrqType type, bool memory_check)
+{
+    char *s = (char *)malloc(size);
+    
+    if (s == (char *)NULL) {
+        if (memory_check) {
+            error("Failed to allocate memory for %s buffer", type == TxIrq ? "TX" : "RX");
+        }
+        return NoMemory;
+    }
+    
+    if (buffer_count[type] == 0) { // Current buffer empty?
+        free((char *)buffer[type]);
+        buffer[type]      = s;
+        buffer_in[type]   = 0;
+        buffer_out[type]  = 0;
+    }        
+    else { // Copy the current contents into the new buffer.
+        int c, new_in = 0;
+        do {
+            c = __getc(false);
+            if (c != -1) s[new_in++] = (char)c;
+            if (new_in >= size) new_in = 0; // Shouldn't happen, but be sure.
+        }
+        while (c != -1);
+        free((char *)buffer[type]);
+        buffer[type]      = s;
+        buffer_in[type]   = new_in;
+        buffer_out[type]  = 0;
+    }
+    
+    buffer_size[type] = size;
+    return Ok;
+}
+
+}; // namespace AjK ends
diff -r 000000000000 -r 1447d2f773db MODSERIAL/example1.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/example1.cpp	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,120 @@
+#ifdef COMPILE_EXAMPLE1_CODE_MODSERIAL
+
+/*
+ * To run this test program, link p9 to p10 so the Serial loops
+ * back and receives characters it sends.
+ */
+ 
+#include "mbed.h"
+#include "MODSERIAL.h"
+
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+
+MODSERIAL pc(USBTX, USBRX);
+
+/*
+ * As experiement, you can define MODSERIAL as show here and see what
+ * effects it has on the LEDs.
+ *
+ * MODSERIAL uart(TX_PIN, RX_PIN, 512);
+ *   With this, the 512 characters sent can straight into the buffer
+ *   vary quickly. This means LED1 is only on briefly as the TX buffer
+ *   fills.
+ *
+ * MODSERIAL uart(TX_PIN, RX_PIN, 32);
+ *   With this, the buffer is smaller than the default 256 bytes and
+ *   therefore LED1 stays on much longer while the system waits for
+ *   room in the TX buffer.
+ */
+MODSERIAL uart(TX_PIN, RX_PIN);
+
+// This function is called when a character goes from the TX buffer
+// to the Uart THR FIFO register.
+void txCallback(MODSERIAL_IRQ_INFO *q) {
+    led2 = !led2;
+}
+
+// This function is called when TX buffer goes empty
+void txEmpty(MODSERIAL_IRQ_INFO *q) {
+    led2 = 0;
+    pc.puts(" Done. ");
+}
+
+// This function is called when a character goes into the RX buffer.
+void rxCallback(MODSERIAL_IRQ_INFO *q) {
+    led3 = !led3;
+    pc.putc(uart.getc());
+}
+
+int main() {
+    int c = 'A';
+    
+    // Ensure the baud rate for the PC "USB" serial is much
+    // higher than "uart" baud rate below.
+    pc.baud(PC_BAUD);
+    
+    // Use a deliberatly slow baud to fill up the TX buffer
+    uart.baud(1200);
+    
+    uart.attach(&txCallback, MODSERIAL::TxIrq);
+    uart.attach(&rxCallback, MODSERIAL::RxIrq);
+    uart.attach(&txEmpty,    MODSERIAL::TxEmpty);
+    
+    // Loop sending characters. We send 512
+    // which is twice the default TX/RX buffer size.
+    
+    led1 = 1; // Show start of sending with LED1.
+    
+    for (int loop = 0; loop < 512; loop++) {
+        uart.printf("%c", c);        
+        c++;
+        if (c > 'Z') c = 'A';
+    }
+    
+    led1 = 0; // Show the end of sending by switching off LED1.
+    
+    // End program. Flash LED4. Notice how LED 2 and 3 continue
+    // to flash for a short period while the interrupt system 
+    // continues to send the characters left in the TX buffer.
+    
+    while(1) {
+        led4 = !led4;
+        wait(0.25);
+    }
+}
+
+/*
+ * Notes. Here is the sort of output you can expect on your PC/Mac/Linux host
+ * machine that is connected to the "pc" USB serial port.
+ *
+ * ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUV
+ * WXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR
+ * STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN
+ * OPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJ
+ * KLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF
+ * GHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZAB
+ * CDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ Done. R
+ *
+ * Of interest is that last "R" character after the system has said "Done."
+ * This comes from the fact that the TxEmpty callback is made when the TX buffer
+ * becomes empty. MODSERIAL makes use of the fact that the Uarts built into the 
+ * LPC17xx device use a 16 byte FIFO on both RX and TX channels. This means that
+ * when the TxEmpty callback is made, the TX buffer is empty, but that just means
+ * the "last few characters" were written to the TX FIFO. So although the TX
+ * buffer has gone empty, the Uart's transmit system is still sending any remaining
+ * characters from it's TX FIFO. If you want to be truely sure all the characters
+ * you have sent have left the Mbed then call txIsBusy(); This function will
+ * return true if characters are still being sent. If it returns false after
+ * the Tx buffer is empty then all your characters have been sent.
+ *
+ * In a similar way, when characters are received into the RX FIFO, the entire
+ * FIFO contents is moved to the RX buffer, assuming there is room left in the
+ * RX buffer. If there is not, any remaining characters are left in the RX FIFO
+ * and will be moved to the RX buffer on the next interrupt or when the running 
+ * program removes a character(s) from the RX buffer with the getc() method.
+ */
+ 
+#endif
diff -r 000000000000 -r 1447d2f773db MODSERIAL/example2.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/example2.cpp	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,167 @@
+/*
+    Copyright (c) 2011 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.
+    
+    @file          example2.cpp 
+    @purpose       Demos a simple messaging system.
+    @version       see ChangeLog.c
+    @date          Jan 2011
+    @author        Andy Kirkham
+*/
+
+/*
+    This example demostrates a simple "messaging" system. You can use it with
+    a terminal program to test it out or write a cusom C#/C++/VB/etc program
+    to read and write messages to or from the Mbed. The default baud rate in
+    this example is 115200.
+    
+    In this example, the LEDs are controlled and pins p21 to p24 are set as
+    InterruptIn and send messages out when their value changes.
+    
+    To use, hook up the MBed USB and open your fav terminal. All messages
+    end with the \n character, don't forget to hit carriage return!. 
+    As an example:-
+        
+        to switch on LED1 send LED1:1\n, off is LED1:0\n and toggle is LED1:2\n
+        to switch on LED2 send LED2:1\n, off is LED2:0\n and toggle is LED2:2\n
+        to switch on LED3 send LED3:1\n, off is LED3:0\n and toggle is LED3:2\n
+        to switch on LED4 send LED4:1\n, off is LED4:0\n and toggle is LED4:2\n
+        
+    When a pin change on p21 to p24 happens, a message is sent. As an example
+    when p21 goes low PIN21:0\n is sent, when goes high PIN21:1\n is sent.
+    
+    Note, the InterruptIn pins p21 to p24 are setup to have pullups. This means
+    they are high. To activate them use a wire to short the pin to 0volts.
+    
+    If you find that p21 to p24 sent a lot of on/off/on/off then it's probably
+    due to "bounce". If you are connecting a mechanical switch to a pin you
+    may prefer to use the PinDetect library rather than using InterruptIn.
+    @see http://mbed.org/users/AjK/libraries/PinDetect/latest
+    
+    One point you may notice. Incoming messages are processed via main()'s
+    while(1) loop whereas pin changes have their messages directly sent.
+    The reason for this is when MODSERIAL makes callbacks to your application
+    it is in "interrupt context". And one thing you want to avoid is spending
+    lots of CPU time in that context. So, the callback moves the message from
+    the input buffer to a local holding buffer and it then sets a bool flag
+    which tells main()'s while(1) loop to process that buffer. This means the 
+    time spent doing the real incoming message handing is within your program
+    and not within MODSERIAL's interrupt context. So you may ask, why not do
+    the same for out going messages? Well, because MODSERIAL output buffers
+    all your sent content then sending chars is very fast. MODSERIAL handles
+    all the nitty gritty bits for you. You can just send. This example uses
+    puts() to send the message. If you can, always try and use sprintf()+puts()
+    rathe than printf(), printf() is known to often screw things up when used
+    within an interrupt context. Better still, just use puts() and do away
+    with any of the crappy ?printf() calls if possible. But I found the code
+    below to work fine even at 115200baud.
+    
+*/
+
+
+#ifdef COMPILE_EXAMPLE1_CODE_MODSERIAL
+
+#include "mbed.h"
+#include "MODSERIAL.h"
+
+#define MESSAGE_BUFFER_SIZE 32
+
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+
+InterruptIn P21(p21);
+InterruptIn P22(p22);
+InterruptIn P23(p23);
+InterruptIn P24(p24);
+
+MODSERIAL messageSystem(USBTX, USBRX);
+
+char messageBufferIncoming[MESSAGE_BUFFER_SIZE];
+char messageBufferOutgoing[MESSAGE_BUFFER_SIZE];
+bool messageReceived;
+
+void messageReceive(MODSERIAL_IRQ_INFO *q) {
+    MODSERIAL *sys = q->serial;
+    sys->move(messageBufferIncoming, MESSAGE_BUFFER_SIZE);
+    messageReceived = true;
+    return 0;
+}
+
+void messageProcess(void) {
+         if (!strncmp(messageBufferIncoming, "LED1:1", sizeof("LED1:1")-1)) led1 = 1;
+    else if (!strncmp(messageBufferIncoming, "LED1:0", sizeof("LED1:0")-1)) led1 = 0;
+    else if (!strncmp(messageBufferIncoming, "LED1:2", sizeof("LED1:2")-1)) led1 = !led1;
+    
+    else if (!strncmp(messageBufferIncoming, "LED2:1", sizeof("LED2:1")-1)) led2 = 1;
+    else if (!strncmp(messageBufferIncoming, "LED2:0", sizeof("LED2:0")-1)) led2 = 0;
+    else if (!strncmp(messageBufferIncoming, "LED2:2", sizeof("LED2:2")-1)) led2 = !led2;
+    
+    else if (!strncmp(messageBufferIncoming, "LED3:1", sizeof("LED3:1")-1)) led3 = 1;
+    else if (!strncmp(messageBufferIncoming, "LED3:0", sizeof("LED3:0")-1)) led3 = 0;
+    else if (!strncmp(messageBufferIncoming, "LED3:2", sizeof("LED3:2")-1)) led3 = !led3;
+    
+    else if (!strncmp(messageBufferIncoming, "LED4:1", sizeof("LED4:1")-1)) led4 = 1;
+    else if (!strncmp(messageBufferIncoming, "LED4:0", sizeof("LED4:0")-1)) led4 = 0;
+    else if (!strncmp(messageBufferIncoming, "LED4:2", sizeof("LED4:2")-1)) led4 = !led4;
+    
+    messageReceived = false;
+}
+
+#define PIN_MESSAGE_SEND(x,y) \
+    sprintf(messageBufferOutgoing,"PIN%02d:%d\n",x,y);\
+    messageSystem.puts(messageBufferOutgoing);
+
+void pin21Rise(void) { PIN_MESSAGE_SEND(21, 1); }
+void pin21Fall(void) { PIN_MESSAGE_SEND(21, 0); }
+void pin22Rise(void) { PIN_MESSAGE_SEND(22, 1); }
+void pin22Fall(void) { PIN_MESSAGE_SEND(22, 0); }
+void pin23Rise(void) { PIN_MESSAGE_SEND(23, 1); }
+void pin23Fall(void) { PIN_MESSAGE_SEND(23, 0); }
+void pin24Rise(void) { PIN_MESSAGE_SEND(24, 1); }
+void pin24Fall(void) { PIN_MESSAGE_SEND(24, 0); }
+
+int main() {
+
+    messageReceived = false;
+    messageSystem.baud(115200);
+    messageSystem.attach(&messageReceive, MODSERIAL::RxAutoDetect);
+    messageSystem.autoDetectChar('\n'); 
+
+    // Enable pullup resistors on pins.
+    P21.mode(PullUp); P22.mode(PullUp); P23.mode(PullUp); P24.mode(PullUp);
+    
+    // Fix Mbed library bug, see http://mbed.org/forum/bugs-suggestions/topic/1498
+    LPC_GPIOINT->IO2IntClr = (1UL << 5) | (1UL << 4) | (1UL << 3) | (1UL << 2); 
+    
+    // Attach InterruptIn pin callbacks.
+    P21.rise(&pin21Rise); P21.fall(&pin21Fall);
+    P22.rise(&pin22Rise); P22.fall(&pin22Fall);
+    P23.rise(&pin23Rise); P23.fall(&pin23Fall);
+    P24.rise(&pin24Rise); P24.fall(&pin24Fall);
+    
+    while(1) {
+        // Process incoming messages.
+        if (messageReceived) messageProcess();
+    }
+}
+
+#endif
diff -r 000000000000 -r 1447d2f773db MODSERIAL/example3a.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/example3a.cpp	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,83 @@
+/*
+    Copyright (c) 2011 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.
+    
+    @file          example3.cpp 
+    @purpose       Demos a simple filter.
+    @version       see ChangeLog.c
+    @author        Andy Kirkham
+*/
+
+/*
+    This example shows how to use the new callback system. In the old system
+    Mbed's FunctionPointer[1] type was used to store abd make calls to callbacks.
+    However, that limits the callback function prototype to void func(void);
+    which means we cannot pass parameters.
+    
+    This latest version of MODSERIAL now uses its own callback object. This allows
+    the passing of a pointer to a class that holds information about the MODSERIAL
+    object making the callback. As of version 1.18 one critcal piece of information
+    is passed, a pointer to the MODSERIAL object. This allows callbacks to use the
+    MODSERIAL functions and data.
+        
+    Additionally, since MODSERIAL and the callback parameter class MODSERIAL_IRQ_INFO
+    are friends, MODSERIAL_IRQ_INFO can access the protected functions of MODSERIAL.
+    This is used to ensure functions that can only be called during a callback
+    can be invoked from a callback. 
+    
+    [1] http://mbed.org/projects/libraries/svn/mbed/trunk/FunctionPointer.h    
+*/
+
+#ifdef COMPILE_EXAMPLE3_CODE_MODSERIAL
+
+#include "mbed.h"
+#include "MODSERIAL.h"
+
+DigitalOut led1(LED1);
+
+MODSERIAL pc(USBTX, USBRX);
+
+// The following callback is defined in example3b.cpp
+//! @see example3b.cpp
+void rxCallback(MODSERIAL_IRQ_INFO *info);
+
+int main() {
+    
+    int life_counter = 0;
+    
+    pc.baud(115200);
+    
+    pc.attach(&rxCallback, MODSERIAL::RxIrq);
+
+    while(1) {
+        // Echo back any chars we get except 'A' which is filtered by the rxCallback.
+        if (pc.readable()) {
+            pc.putc(pc.getc());
+        }
+        
+        // Toggle LED1 every so often to show we are alive.
+        if (life_counter++ == 1000000) {
+            life_counter = 0;
+            led1 = !led1;
+        }
+    }
+}
+
+#endif
diff -r 000000000000 -r 1447d2f773db MODSERIAL/example3b.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/example3b.cpp	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,78 @@
+/*
+    Copyright (c) 2011 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.
+    
+    @file          example3b.cpp 
+    @purpose       Demos a simple filter.
+    @version       see ChangeLog.c
+    @author        Andy Kirkham
+*/
+
+/*
+    This example shows how to use the new callback system. In the old system
+    Mbed's FunctionPointer[1] type was used to store abd make calls to callbacks.
+    However, that limits the callback function prototype to void func(void);
+    which means we cannot pass parameters.
+    
+    This latest version of MODSERIAL now uses its own callback object. This allows
+    the passing of a pointer to a class that holds information about the MODSERIAL
+    object making the callback. As of version 1.18 one critcal piece of information
+    is passed, a pointer to the MODSERIAL object. This allows callbacks to use the
+    MODSERIAL functions and data.
+        
+    Additionally, since MODSERIAL and the callback parameter class MODSERIAL_IRQ_INFO
+    are friends, MODSERIAL_IRQ_INFO can access the protected functions of MODSERIAL.
+    This is used to ensure functions that can only be called during a callback
+    can be invoked from a callback. 
+    
+    [1] http://mbed.org/projects/libraries/svn/mbed/trunk/FunctionPointer.h    
+*/
+
+
+#ifdef COMPILE_EXAMPLE3_CODE_MODSERIAL
+
+#include "mbed.h"
+#include "MODSERIAL.h"
+
+void rxCallback(MODSERIAL_IRQ_INFO *info) {
+
+    // Get the pointer to our MODSERIAL object that invoked this callback.
+    MODSERIAL *pc = info->serial;
+    
+    // info->serial points at the MODSERIAL instance so we can use it to call
+    // any of the public MODSERIAL functions that are normally available. So
+    // there's now no need to use the global version (pc in our case) inside
+    // callback functions.    
+    char c = pc->rxGetLastChar(); // Where local pc variable is a pointer to the global MODSERIAL pc object.
+    
+    // The following is rather daft but demos the point.
+    // Don't allow the letter "A" go into the RX buffer.
+    // Basically acts as a filter to remove the letter "A" 
+    // if it goes into the RX buffer.
+    if (c == 'A') {
+        // Note, we call the MODSERIAL_IRQ_INFO::rxDiscardLastChar() public function which
+        // is permitted access to the protected version of MODSERIAL::rxDiscardLastChar()
+        // within MODSERIAL (because they are friends). This ensures rxDiscardLastChar()
+        // can only be called within an rxCallback function. 
+        info->rxDiscardLastChar(); 
+    }
+}
+
+#endif
diff -r 000000000000 -r 1447d2f773db MODSERIAL/example_dma.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/example_dma.cpp	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,144 @@
+#ifdef COMPILE_EXAMPLE_CODE_MODSERIAL_MODDMA
+
+/*
+ * To run this test program, link p9 to p10 so the Serial loops
+ * back and receives characters it sends.
+ */
+ 
+#include "mbed.h"
+
+/* Note, this example requires that you also import into the Mbed
+   compiler the MODDMA project as well as MODSERIAL
+   http://mbed.org/users/AjK/libraries/MODDMA/latest 
+   MODDMA.h MUST come before MODSERIAL.h */
+#include "MODDMA.h"     // <--- Declare first
+#include "MODSERIAL.h"  // Flollowed by MODSERIAL
+
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+
+MODSERIAL pc(USBTX, USBRX);
+
+/*
+ * As experiement, you can define MODSERIAL as show here and see what
+ * effects it has on the LEDs.
+ *
+ * MODSERIAL uart(TX_PIN, RX_PIN, 512);
+ *   With this, the 512 characters sent can straight into the buffer
+ *   vary quickly. This means LED1 is only on briefly as the TX buffer
+ *   fills.
+ *
+ * MODSERIAL uart(TX_PIN, RX_PIN, 32);
+ *   With this, the buffer is smaller than the default 256 bytes and
+ *   therefore LED1 stays on much longer while the system waits for
+ *   room in the TX buffer.
+ */
+MODSERIAL uart(TX_PIN, RX_PIN);
+
+MODDMA dma;
+
+// This function is called when a character goes from the TX buffer
+// to the Uart THR FIFO register.
+void txCallback(void) {
+    led2 = !led2;
+}
+
+// This function is called when TX buffer goes empty
+void txEmpty(void) {
+    led2 = 0;
+    pc.puts(" Done. ");
+}
+
+void dmaComplete(void) {
+    led1 = 1;
+}
+
+// This function is called when a character goes into the RX buffer.
+void rxCallback(void) {
+    led3 = !led3;
+    pc.putc(uart.getc());
+}
+
+int main() {
+    char s1[] = " *DMA* *DMA* *DMA* *DMA* *DMA* *DMA* *DMA* ";
+    int c = 'A';
+    
+    // Tell MODSERIAL where the MODDMA controller is.
+    pc.MODDMA( &dma );
+    
+    // Ensure the baud rate for the PC "USB" serial is much
+    // higher than "uart" baud rate below.
+    pc.baud( PC_BAUD );
+    
+    // Use a deliberatly slow baud to fill up the TX buffer
+    uart.baud(1200);
+    
+    uart.attach( &txCallback, MODSERIAL::TxIrq );
+    uart.attach( &rxCallback, MODSERIAL::RxIrq );
+    uart.attach( &txEmpty,    MODSERIAL::TxEmpty );
+    
+    // Loop sending characters. We send 512
+    // which is twice the default TX/RX buffer size.
+    
+    led1 = 0;
+    
+    // Send the buffer s using DMA channel 7
+    pc.attach_dmaSendComplete( &dmaComplete );
+    pc.dmaSend( s1, sizeof(s1), MODDMA::Channel_7 );
+    
+    for (int loop = 0; loop < 512; loop++) {
+        uart.printf("%c", c);        
+        c++;
+        if (c > 'Z') c = 'A';
+    }
+    
+    led1 = 0; // Show the end of sending by switching off LED1.
+    
+    // End program. Flash LED4. Notice how LED 2 and 3 continue
+    // to flash for a short period while the interrupt system 
+    // continues to send the characters left in the TX buffer.
+    
+    while(1) {
+        led4 = !led4;
+        wait(0.25);
+    }
+}
+
+/*
+ * Notes. Here is the sort of output you can expect on your PC/Mac/Linux host
+ * machine that is connected to the "pc" USB serial port.
+ *
+ *  *DMA* *DMA* *DMA* *DMA* *DMA* *DMA* *DMA* ABCDEFGHIJKLMNOPQRSTUVWXYZABCDE
+ * FGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZA
+ * BCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVW
+ * XYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRS
+ * TUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNO
+ * PQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJK
+ * LMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFG
+ * HIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ Done. R
+ *
+ * Note how the DMA blocks the TX buffer sending under standard interrupt control.
+ * Not until the DMA transfer is complete will "normal" buffered TX sending resume.
+ *
+ * Of interest is that last "R" character after the system has said "Done."
+ * This comes from the fact that the TxEmpty callback is made when the TX buffer
+ * becomes empty. MODSERIAL makes use of the fact that the Uarts built into the 
+ * LPC17xx device use a 16 byte FIFO on both RX and TX channels. This means that
+ * when the TxEmpty callback is made, the TX buffer is empty, but that just means
+ * the "last few characters" were written to the TX FIFO. So although the TX
+ * buffer has gone empty, the Uart's transmit system is still sending any remaining
+ * characters from it's TX FIFO. If you want to be truely sure all the characters
+ * you have sent have left the Mbed then call txIsBusy(); This function will
+ * return true if characters are still being sent. If it returns false after
+ * the Tx buffer is empty then all your characters have been sent.
+ *
+ * In a similar way, when characters are received into the RX FIFO, the entire
+ * FIFO contents is moved to the RX buffer, assuming there is room left in the
+ * RX buffer. If there is not, any remaining characters are left in the RX FIFO
+ * and will be moved to the RX buffer on the next interrupt or when the running 
+ * program removes a character(s) from the RX buffer with the getc() method.
+ */
+ 
+#endif
diff -r 000000000000 -r 1447d2f773db UM6_config/UM6_config.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UM6_config/UM6_config.h	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,479 @@
+/* ------------------------------------------------------------------------------
+  File: UM6_config.h
+  Author: CH Robotics
+  Version: 1.0
+
+  Description: Preprocessor definitions and function declarations for UM6 configuration
+------------------------------------------------------------------------------ */
+#ifndef __UM6_CONFIG_H
+#define __UM6_CONFIG_H
+#include "UM6_usart.h"
+
+
+MODSERIAL um6_uart(p9, p10);    // UM6 SERIAL OVER UART Pin 9 & Pin 10
+
+
+
+
+
+
+
+
+// CONFIG_ARRAY_SIZE and DATA_ARRAY_SIZE specify the number of 32 bit configuration and data registers used by the firmware
+// (Note: The term "register" is used loosely here.  These "registers" are not actually registers in the same sense of a
+// microcontroller register.  They are simply index locations into arrays stored in global memory.  Data and configuration
+// parameters are stored in arrays because it allows a common communication protocol to be used to access all data and
+// configuration.  The software communicating with the sensor needs only specify the register address, and the communication
+// software running on the sensor knows exactly where to find it - it needn't know what the data is.  The software communicatin
+// with the sensor, on the other hand, needs to know what it is asking for (naturally...)
+// This setup makes it easy to make more data immediately available when needed - simply increase the array size, add code in
+// the firmware that writes data to the new array location, and then make updates to the firmware definition on the PC side.
+#define    CONFIG_ARRAY_SIZE        44
+#define    DATA_ARRAY_SIZE          33
+#define    COMMAND_COUNT             9
+
+//
+#define    CONFIG_REG_START_ADDRESS       0
+#define    DATA_REG_START_ADDRESS        85
+#define    COMMAND_START_ADDRESS        170
+
+// These preprocessor definitions make it easier to access specific configuration parameters in code
+// They specify array locations associated with each register name.  Note that in the comments below, many of the values are
+// said to be 32-bit IEEE floating point.  Obviously this isn't directly the case, since the arrays are actually 32-bit unsigned
+// integer arrays.  Bit for bit, the data does correspond to the correct floating point value.  Since you can't cast ints as floats,
+// special conversion has to happen to copy the float data to and from the array.
+// Starting with configuration register locations...
+
+
+// Now for data register locations.
+// In the communication protocol, data registers are labeled with number ranging from 128 to 255.  The value of 128 will be subtracted from these numbers
+// to produce the actual array index labeled below
+#define    UM6_STATUS                DATA_REG_START_ADDRESS                // Status register defines error codes with individual bits
+#define    UM6_GYRO_RAW_XY        (DATA_REG_START_ADDRESS    + 1)        // Raw gyro data is stored in 16-bit signed integers
+#define    UM6_GYRO_RAW_Z            (DATA_REG_START_ADDRESS + 2)
+#define    UM6_ACCEL_RAW_XY        (DATA_REG_START_ADDRESS + 3)        // Raw accel data is stored in 16-bit signed integers
+#define    UM6_ACCEL_RAW_Z        (DATA_REG_START_ADDRESS + 4)
+#define    UM6_MAG_RAW_XY            (DATA_REG_START_ADDRESS + 5)        // Raw mag data is stored in 16-bit signed integers
+#define    UM6_MAG_RAW_Z            (DATA_REG_START_ADDRESS + 6)
+#define    UM6_GYRO_PROC_XY        (DATA_REG_START_ADDRESS + 7)        // Processed gyro data has scale factors applied and alignment correction performed.  Data is 16-bit signed integer.
+#define    UM6_GYRO_PROC_Z        (DATA_REG_START_ADDRESS + 8)
+#define    UM6_ACCEL_PROC_XY        (DATA_REG_START_ADDRESS + 9)        // Processed accel data has scale factors applied and alignment correction performed.  Data is 16-bit signed integer.
+#define    UM6_ACCEL_PROC_Z        (DATA_REG_START_ADDRESS + 10)
+#define    UM6_MAG_PROC_XY        (DATA_REG_START_ADDRESS + 11)        // Processed mag data has scale factors applied and alignment correction performed.  Data is 16-bit signed integer.
+#define    UM6_MAG_PROC_Z            (DATA_REG_START_ADDRESS + 12)
+#define    UM6_EULER_PHI_THETA    (DATA_REG_START_ADDRESS + 13)        // Euler angles are 32-bit IEEE floating point
+#define    UM6_EULER_PSI            (DATA_REG_START_ADDRESS + 14)
+#define    UM6_QUAT_AB                (DATA_REG_START_ADDRESS + 15)        // Quaternions are 16-bit signed integers.
+#define    UM6_QUAT_CD                (DATA_REG_START_ADDRESS + 16)
+#define    UM6_ERROR_COV_00        (DATA_REG_START_ADDRESS + 17)        // Error covariance is a 4x4 matrix of 32-bit IEEE floating point values
+#define    UM6_ERROR_COV_01        (DATA_REG_START_ADDRESS + 18)
+#define    UM6_ERROR_COV_02        (DATA_REG_START_ADDRESS + 19)
+#define    UM6_ERROR_COV_03        (DATA_REG_START_ADDRESS + 20)
+#define    UM6_ERROR_COV_10        (DATA_REG_START_ADDRESS + 21)
+#define    UM6_ERROR_COV_11        (DATA_REG_START_ADDRESS + 22)
+#define    UM6_ERROR_COV_12        (DATA_REG_START_ADDRESS + 23)
+#define    UM6_ERROR_COV_13        (DATA_REG_START_ADDRESS + 24)
+#define    UM6_ERROR_COV_20        (DATA_REG_START_ADDRESS + 25)
+#define    UM6_ERROR_COV_21        (DATA_REG_START_ADDRESS + 26)
+#define    UM6_ERROR_COV_22        (DATA_REG_START_ADDRESS + 27)
+#define    UM6_ERROR_COV_23        (DATA_REG_START_ADDRESS + 28)
+#define    UM6_ERROR_COV_30        (DATA_REG_START_ADDRESS + 29)
+#define    UM6_ERROR_COV_31        (DATA_REG_START_ADDRESS + 30)
+#define    UM6_ERROR_COV_32        (DATA_REG_START_ADDRESS + 31)
+#define    UM6_ERROR_COV_33        (DATA_REG_START_ADDRESS + 32)
+
+
+
+#define    UM6_GET_FW_VERSION    COMMAND_START_ADDRESS            // Causes the UM6 to report the firmware revision
+#define    UM6_FLASH_COMMIT        (COMMAND_START_ADDRESS + 1)    // Causes the UM6 to write all configuration values to FLASH
+#define    UM6_ZERO_GYROS            (COMMAND_START_ADDRESS + 2)    // Causes the UM6 to start a zero gyros command
+#define    UM6_RESET_EKF             (COMMAND_START_ADDRESS + 3)    // Causes the UM6 to reset the EKF
+#define    UM6_GET_DATA             (COMMAND_START_ADDRESS + 4)    // Causes the UM6 to transmit a data packet containing data from all enabled channels
+#define    UM6_SET_ACCEL_REF        (COMMAND_START_ADDRESS + 5)    // Causes the UM6 to set the current measured accel data to the reference vector
+#define    UM6_SET_MAG_REF        (COMMAND_START_ADDRESS + 6)    // Causes the UM6 to set the current measured magnetometer data to the reference vector
+#define    UM6_RESET_TO_FACTORY    (COMMAND_START_ADDRESS + 7)    // Causes the UM6 to load default factory settings
+ 
+#define    UM6_SAVE_FACTORY        (COMMAND_START_ADDRESS + 8)    // Causes the UM6 to save the current settings to the factory flash location
+ 
+#define    UM6_USE_CONFIG_ADDRESS        0
+#define    UM6_USE_FACTORY_ADDRESS        1
+ 
+#define    UM6_BAD_CHECKSUM            253                                // Sent if the UM6 receives a packet with a bad checksum
+#define    UM6_UNKNOWN_ADDRESS        254                                // Sent if the UM6 receives a packet with an unknown address
+#define    UM6_INVALID_BATCH_SIZE    255                                // Sent if a requested batch read or write operation would go beyond the bounds of the config or data array
+
+
+
+
+
+
+/*******************************************************************************
+* Function Name  : ComputeChecksum
+* Input          : USARTPacket* new_packet
+* Output         : None
+* Return         : uint16_t
+* Description    : Returns the two byte sum of all the individual bytes in the
+                         given packet.
+*******************************************************************************/
+uint16_t ComputeChecksum( USARTPacket* new_packet ) {
+    int32_t index;
+    uint16_t checksum = 0x73 + 0x6E + 0x70 + new_packet->PT + new_packet->address;
+
+    for ( index = 0; index < new_packet->data_length; index++ ) {
+        checksum += new_packet->packet_data[index];
+    }
+    return checksum;
+}
+
+
+
+
+
+static USARTPacket new_packet;
+
+// Flag for storing the current USART state
+uint8_t gUSART_State = USART_STATE_WAIT;
+
+
+struct UM6{
+float Gyro_Proc_X;
+float Gyro_Proc_Y;
+float Gyro_Proc_Z;
+float Accel_Proc_X;
+float Accel_Proc_Y;
+float Accel_Proc_Z;
+float Mag_Proc_X;
+float Mag_Proc_Y;
+float Mag_Proc_Z;
+float Roll;
+float Pitch;
+float Yaw;
+};
+UM6 data;
+
+
+
+
+void Process_um6_packet() {
+
+int16_t MY_DATA_GYRO_PROC_X;
+int16_t MY_DATA_GYRO_PROC_Y;
+int16_t MY_DATA_GYRO_PROC_Z;
+int16_t MY_DATA_ACCEL_PROC_X;
+int16_t MY_DATA_ACCEL_PROC_Y;
+int16_t MY_DATA_ACCEL_PROC_Z;
+int16_t MY_DATA_MAG_PROC_X;
+int16_t MY_DATA_MAG_PROC_Y;
+int16_t MY_DATA_MAG_PROC_Z;
+int16_t MY_DATA_EULER_PHI;
+int16_t MY_DATA_EULER_THETA;
+int16_t MY_DATA_EULER_PSI;
+
+
+
+static uint8_t data_counter = 0;
+
+
+
+            // The next action should depend on the USART state.
+            switch ( gUSART_State ) {
+                    // USART in the WAIT state.  In this state, the USART is waiting to see the sequence of bytes
+                    // that signals a new incoming packet.
+                case USART_STATE_WAIT:
+                    if ( data_counter == 0 ) {     // Waiting on 's' character
+                        if ( um6_uart.getc() == 's' ) {
+
+                            data_counter++;
+                        } else {
+                            data_counter = 0;
+                        }
+                    } else if ( data_counter == 1 ) {    // Waiting on 'n' character
+                        if ( um6_uart.getc() == 'n' ) {
+                            data_counter++;
+
+                        } else {
+                            data_counter = 0;
+                        }
+                    } else if ( data_counter == 2 ) {    // Waiting on 'p' character
+                        if ( um6_uart.getc() == 'p' ) {
+                            // The full 'snp' sequence was received.  Reset data_counter (it will be used again
+                            // later) and transition to the next state.
+                            data_counter = 0;
+                            gUSART_State = USART_STATE_TYPE;
+
+                        } else {
+                            data_counter = 0;
+                        }
+                    }
+                    break;
+
+                    // USART in the TYPE state.  In this state, the USART has just received the sequence of bytes that
+                    // indicates a new packet is about to arrive.  Now, the USART expects to see the packet type.
+                case USART_STATE_TYPE:
+
+                    new_packet.PT = um6_uart.getc();
+
+                    gUSART_State = USART_STATE_ADDRESS;
+
+                    break;
+
+                    // USART in the ADDRESS state.  In this state, the USART expects to receive a single byte indicating
+                    // the address that the packet applies to
+                case USART_STATE_ADDRESS:
+                    new_packet.address = um6_uart.getc();
+                    
+                    // For convenience, identify the type of packet this is and copy to the packet structure
+                    // (this will be used by the packet handler later)
+                    if ( (new_packet.address >= CONFIG_REG_START_ADDRESS) && (new_packet.address < DATA_REG_START_ADDRESS) ) {
+                        new_packet.address_type = ADDRESS_TYPE_CONFIG;
+                    } else if ( (new_packet.address >= DATA_REG_START_ADDRESS) && (new_packet.address < COMMAND_START_ADDRESS) ) {
+                        new_packet.address_type = ADDRESS_TYPE_DATA;
+                    } else {
+                        new_packet.address_type = ADDRESS_TYPE_COMMAND;
+                    }
+
+                    // Identify the type of communication this is (whether reading or writing to a data or configuration register, or sending a command)
+                    // If this is a read operation, jump directly to the USART_STATE_CHECKSUM state - there is no more data in the packet
+                    if ( (new_packet.PT & PACKET_HAS_DATA) == 0 ) {
+                        gUSART_State = USART_STATE_CHECKSUM;
+                    }
+
+                    // If this is a write operation, go to the USART_STATE_DATA state to read in the relevant data
+                    else {
+                        gUSART_State = USART_STATE_DATA;
+                        // Determine the expected number of bytes in this data packet based on the packet type.  A write operation
+                        // consists of 4 bytes unless it is a batch operation, in which case the number of bytes equals 4*batch_size,
+                        // where the batch size is also given in the packet type byte.
+                        if ( new_packet.PT & PACKET_IS_BATCH ) {
+                            new_packet.data_length = 4*((new_packet.PT >> 2) & PACKET_BATCH_LENGTH_MASK);
+
+                        } else {
+                            new_packet.data_length = 4;
+                        }
+                    }
+                    break;
+
+                    // USART in the DATA state.  In this state, the USART expects to receive new_packet.length bytes of
+                    // data.
+                case USART_STATE_DATA:
+                    new_packet.packet_data[data_counter] =  um6_uart.getc();
+                    data_counter++;
+
+                    // If the expected number of bytes has been received, transition to the CHECKSUM state.
+                    if ( data_counter == new_packet.data_length ) {
+                        // Reset data_counter, since it will be used in the CHECKSUM state.
+                        data_counter = 0;
+                        gUSART_State = USART_STATE_CHECKSUM;
+                    }
+                    break;
+
+
+
+                    // USART in CHECKSUM state.  In this state, the entire packet has been received, with the exception
+                    // of the 16-bit checksum.
+                case USART_STATE_CHECKSUM:
+                    // Get the highest-order byte
+                    if ( data_counter == 0 ) {
+                        new_packet.checksum = ((uint16_t)um6_uart.getc() << 8);
+                        data_counter++;
+                    } else { // ( data_counter == 1 )
+                        // Get lower-order byte
+                        new_packet.checksum = new_packet.checksum | ((uint16_t)um6_uart.getc() & 0x0FF);
+
+                        // Both checksum bytes have been received.  Make sure that the checksum is valid.
+                        uint16_t checksum = ComputeChecksum( &new_packet );
+
+
+
+                        // If checksum does not match, exit function
+                        if ( checksum != new_packet.checksum ) {
+                            return;
+                        }   // end if(checksum check)
+
+
+
+                        else
+
+                        {
+
+                            //  Packet was received correctly.
+
+                            //-----------------------------------------------------------------------------------------------
+                            //-----------------------------------------------------------------------------------------------
+                            //
+                            // CHECKSUM WAS GOOD SO GET ARE DATA!!!!!!!!!!!!
+
+
+                            // IF DATA ADDRESS
+                            if  (new_packet.address_type == ADDRESS_TYPE_DATA) {
+
+                                //------------------------------------------------------------
+                                // UM6_GYRO_PROC_XY (0x5C)
+                                // To convert the register data from 16-bit 2's complement integers to actual angular rates in degrees
+                                // per second, the data should be multiplied by the scale factor 0.0610352 as shown below
+                                // angular_rate = register_data*0.0610352
+
+                                if (new_packet.address == UM6_GYRO_PROC_XY) {
+
+                                    // GYRO_PROC_X
+                                    MY_DATA_GYRO_PROC_X = (int16_t)new_packet.packet_data[0]<<8; //bitshift it
+                                    MY_DATA_GYRO_PROC_X |= new_packet.packet_data[1];
+                                    data.Gyro_Proc_X = MY_DATA_GYRO_PROC_X*0.0610352;
+
+                                    MY_DATA_GYRO_PROC_Y = (int16_t)new_packet.packet_data[2]<<8; //bitshift it
+                                    MY_DATA_GYRO_PROC_Y |= new_packet.packet_data[3];
+                                    data.Gyro_Proc_Y = MY_DATA_GYRO_PROC_Y*0.0610352;
+
+
+                                    //------------------------------------------------------------
+
+
+                                    //------------------------------------------------------------
+                                    // UM6_GYRO_PROC_Z (0x5D)
+                                    // To convert the register data from a 16-bit 2's complement integer to the actual angular rate in
+                                    // degrees per second, the data should be multiplied by the scale factor 0.0610352 as shown below.
+
+
+                                    // GYRO_PROC_Z
+                                    MY_DATA_GYRO_PROC_Z = (int16_t)new_packet.packet_data[4]<<8; //bitshift it
+                                    MY_DATA_GYRO_PROC_Z |= new_packet.packet_data[5];;
+                                    data.Gyro_Proc_Z = MY_DATA_GYRO_PROC_Z*0.0610352;
+                                    
+                                    
+                                }   // end if(MY_DATA_GYRO_PROC)
+                                //------------------------------------------------------------
+
+
+                                //------------------------------------------------------------
+                                // UM6_ACCEL_PROC_XY (0x5E)
+                                // To convert the register data from 16-bit 2's complement integers to actual acceleration in gravities,
+                                // the data should be multiplied by the scale factor 0.000183105 as shown below.
+                                // acceleration = register_data* 0.000183105
+                                if (new_packet.address == UM6_ACCEL_PROC_XY) {
+
+                                    // ACCEL_PROC_X
+                                    MY_DATA_ACCEL_PROC_X = (int16_t)new_packet.packet_data[0]<<8; //bitshift it
+                                    MY_DATA_ACCEL_PROC_X |= new_packet.packet_data[1];
+                                    data.Accel_Proc_X = MY_DATA_ACCEL_PROC_X*0.000183105;
+
+                                    // ACCEL_PROC_Y
+                                    MY_DATA_ACCEL_PROC_Y = (int16_t)new_packet.packet_data[2]<<8; //bitshift it
+                                    MY_DATA_ACCEL_PROC_Y |= new_packet.packet_data[3];
+                                    data.Accel_Proc_Y = MY_DATA_ACCEL_PROC_Y*0.000183105;
+
+                                    //------------------------------------------------------------
+
+
+                                    //------------------------------------------------------------
+                                    // UM6_ACCEL_PROC_Z (0x5F)
+                                    // To convert the register data from a 16-bit 2's complement integer to the actual acceleration in
+                                    // gravities, the data should be multiplied by the scale factor 0.000183105 as shown below.
+
+                                    // ACCEL_PROC_Z
+                                    MY_DATA_ACCEL_PROC_Z = (int16_t)new_packet.packet_data[4]<<8; //bitshift it
+                                    MY_DATA_ACCEL_PROC_Z |= new_packet.packet_data[5];
+                                    data.Accel_Proc_Z = MY_DATA_ACCEL_PROC_Z*0.000183105;
+                                    
+                                }   // end if(MY_DATA_ACCEL_PROC)
+
+                                //------------------------------------------------------------
+
+
+                                //------------------------------------------------------------
+                                // UM6_MAG_PROC_XY (0x60)
+                                // To convert the register data from 16-bit 2's complement integers to a unit-norm (assuming proper
+                                // calibration)  magnetic-field vector, the data should be multiplied by the scale factor 0.000305176 as
+                                // shown below.
+                                // magnetic field = register_data* 0.000305176
+                                if (new_packet.address == UM6_MAG_PROC_XY) {
+
+                                    // MAG_PROC_X
+                                    MY_DATA_MAG_PROC_X = (int16_t)new_packet.packet_data[0]<<8; //bitshift it
+                                    MY_DATA_MAG_PROC_X |= new_packet.packet_data[1];
+                                    data.Mag_Proc_X = MY_DATA_MAG_PROC_X*0.000305176;
+                                    
+
+                                    // MAG_PROC_Y
+                                    MY_DATA_MAG_PROC_Y = (int16_t)new_packet.packet_data[2]<<8; //bitshift it
+                                    MY_DATA_MAG_PROC_Y |= new_packet.packet_data[3];
+                                    data.Mag_Proc_Y = MY_DATA_MAG_PROC_Y*0.000305176;
+
+                                    //------------------------------------------------------------
+
+
+                                    //------------------------------------------------------------
+                                    // UM6_MAG_PROC_Z (0x61)
+                                    // To convert the register data from 16-bit 2's complement integers to a unit-norm (assuming proper
+                                    // calibration)  magnetic-field vector, the data should be multiplied by the scale factor 0.000305176 as
+                                    // shown below.
+                                    // magnetic field = register_data*0.000305176
+
+                                    // MAG_PROC_Z
+                                    MY_DATA_MAG_PROC_Z = (int16_t)new_packet.packet_data[4]<<8; //bitshift it
+                                    MY_DATA_MAG_PROC_Z |= new_packet.packet_data[5];
+                                    data.Mag_Proc_Z = MY_DATA_MAG_PROC_Z*0.000305176;
+
+                                }   // end if(UM6_MAG_PROC)
+                                //------------------------------------------------------------
+
+
+
+                                //------------------------------------------------------------
+                                // UM6_EULER_PHI_THETA (0x62)
+                                // Stores the most recently computed roll (phi) and pitch (theta) angle estimates.  The angle
+                                // estimates are stored as 16-bit 2's complement integers.  To obtain the actual angle estimate in
+                                // degrees, the register data should be multiplied by the scale factor 0.0109863 as shown below
+                                // angle estimate = register_data* 0.0109863
+                                if (new_packet.address == UM6_EULER_PHI_THETA) {
+                                    // EULER_PHI (ROLL)
+                                   MY_DATA_EULER_PHI = (int16_t)new_packet.packet_data[0]<<8; //bitshift it
+                                   MY_DATA_EULER_PHI |= new_packet.packet_data[1];
+                                   data.Roll = MY_DATA_EULER_PHI*0.0109863;
+                                    
+         
+         
+         
+
+                                    // EULER_THETA (PITCH)
+                                    MY_DATA_EULER_THETA = (int16_t)new_packet.packet_data[2]<<8; //bitshift it
+                                    MY_DATA_EULER_THETA |= new_packet.packet_data[3];
+                                    data.Pitch = MY_DATA_EULER_THETA*0.0109863;
+
+                                    //------------------------------------------------------------
+
+                                    //------------------------------------------------------------
+                                    // UM6_EULER_PSI (0x63) (YAW)
+                                    // Stores the most recently computed yaw (psi) angle estimate.  The angle estimate is stored as a 16-
+                                    // bit 2's complement integer.  To obtain the actual angle estimate in degrees, the register data
+                                    // should be multiplied by the scale factor 0.0109863 as shown below
+
+                                    MY_DATA_EULER_PSI = (int16_t)new_packet.packet_data[4]<<8; //bitshift it
+                                    MY_DATA_EULER_PSI |= new_packet.packet_data[5];
+                                    data.Yaw = MY_DATA_EULER_PSI*0.0109863;
+          
+
+                                }    // end if(UM6_EULER_PHI_THETA)
+                                //------------------------------------------------------------
+
+                            }    // end if(ADDRESS_TYPE_DATA)
+
+
+                            // A full packet has been received.
+                            // Put the USART back into the WAIT state and reset
+                            // the data_counter variable so that it can be used to receive the next packet.
+                            data_counter = 0;
+                            gUSART_State = USART_STATE_WAIT;
+
+
+                        }      // end else(GET_DATA)
+ 
+                    }
+                    break;
+            
+            }   //  end switch ( gUSART_State )
+        
+return;
+   
+ }       // end get_gyro_x()
+
+#endif
\ No newline at end of file
diff -r 000000000000 -r 1447d2f773db UM6_usart/UM6_usart.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UM6_usart/UM6_usart.h	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,60 @@
+/* ______________________________________________________________________________________
+ File: UM6_usart.h
+ Author: CH Robotics, adapted for mbed by lhiggs
+ Version: 1.0
+ 
+ Description: Function declarations for USART communucation
+ -------------------------------------------------------------------------------------- */
+ 
+ #ifndef _CHR_USART_H
+ #define _CHR_USART_H
+
+ #define  MAX_PACKET_DATA      40
+ 
+ // Definitions of states for USART receiver state machine (for receiving packets)
+ #define USART_STATE_WAIT       1
+ #define USART_STATE_TYPE       2
+ #define USART_STATE_ADDRESS    3
+ #define USART_STATE_DATA       4
+ #define USART_STATE_CHECKSUM   5
+
+ // Flags for interpreting the packet type byte in communication packets
+ #define PACKET_HAS_DATA            (1 << 7)
+ #define PACKET_IS_BATCH            (1 << 6)
+ #define PACKET_BATCH_LENGTH_MASK   ( 0x0F )
+ 
+ #define PACKET_BATCH_LENGTH_OFFSET     2
+ 
+ #define BATCH_SIZE_2                   2
+ #define BATCH_SIZE_3                   3
+ 
+ #define PACKET_NO_DATA                 0
+ #define PACKET_COMMAND_FAILED      (1 << 0)
+ 
+ 
+ // Define flags for identifying the type of packet address received
+ #define ADDRESS_TYPE_CONFIG            0
+ #define ADDRESS_TYPE_DATA              1
+ #define ADDRESS_TYPE_COMMAND           2
+ 
+ 
+extern uint8_t gUSART_State;
+
+ // Structure for storing TX and RX packet data
+ typedef struct _USARTPacket
+ {
+        uint8_t PT;         // Packet type
+        uint8_t address;    // Packet address
+        uint16_t checksum;  // Checksum
+        
+        // Data included for convenience, but that isn't stored in the packet itself
+        uint8_t data_length;  // Number of bytes in data section
+        uint8_t address_type; // Specified the address type (DATA, CONFIG, OR COMMAND)
+        
+        uint8_t packet_data[MAX_PACKET_DATA];
+        
+ } USARTPacket;
+ 
+uint16_t ComputeChecksum( USARTPacket* new_packet );
+
+#endif
\ No newline at end of file
diff -r 000000000000 -r 1447d2f773db main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,661 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Programm zu Lageregelung der Testplattform mit Hilfe von Reaktionskreiseln.
+// Mit UM6-LT IMU als Trägheitsplattform, XBee-Funkmodul zum seriellen Datenübertraggung und mbed
+// Mikrokontroller als Regelungs- und Stuerungscomputer.
+// Im Programm sind ein PID- und ein PD-Regler implementiert.                                       
+//
+// Datum: 10.01.2014  Autor: Grübel Dimitri
+// 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+#include "mbed.h"                                // MBED HEADER
+#include "MODSERIAL.h"                           // MBED BUFFERED SERIAL HEADER
+#include "UM6_usart.h"                           // UM6 USART HEADER
+#include "UM6_config.h"                          // UM6 CONFIG HEADER
+
+                                                 // KOMMUNIKATIONSART MIT MBED: USB/XBEE
+Serial ios(p28, p27);                            // Serielle Verbi. mit XBee über Pin: tx-28, rx-27
+//Serial ios(USBTX, USBRX);                      // Serielle Verbi. über USB Port vom PC
+
+DigitalOut rst(p11);                             // Digital Reset für the XBee, 200ns für reset
+PwmOut x_kreisel(p21);                           // Pin21-PwmOut ist für Drehung um X-Achse
+PwmOut y_kreisel(p23);                           // Pin23-PwmOut ist für Drehung um Y-Achse
+PwmOut z_kreisel(p22);                           // Pin22-PwmOut ist für Drehung um Z-Achse
+
+                                                 // HIER WIRD PWM EINGESTELLT:
+const float pulsweite = 10.0;                    // Pulsweite des Steuersignals in ms
+const float pwwork = 2.0;                        // Pulsweite des Arbeitssignals in ms
+const float startpw = 0.8;                       // Startpulsweite in ms
+const float pwmfakt = (pwwork - startpw)/200.0;  // Pulsweite pro 1% Leistung
+const float max_leistung = 75.0;                 // Leistungsbegrenzung global in %
+const float min_leistung = 10.0;                 // Notwendige Mindestleistung des Motors in %
+
+const float x_kp_min = 0.0;                      // min/max - Variablen kp für X/Y/Z-Achse
+const float x_kp_max = 3.0;
+const float y_kp_min = 0.0;
+const float y_kp_max = 3.0;
+const float z_kp_min = 0.0;
+const float z_kp_max = 3.0;
+
+const float x_kd_min = 0.0;                      // min/max - Variablen kd für X/Y/Z-Achse
+const float x_kd_max = 3.0;
+const float y_kd_min = 0.0;
+const float y_kd_max = 3.0;
+const float z_kd_min = 0.0;
+const float z_kd_max = 3.0;
+
+const float x_ki_min = 0.0;                      // min/max - Variablen ki für X/Y/Z-Achse
+const float x_ki_max = 0.5;
+const float y_ki_min = 0.0;
+const float y_ki_max = 0.5;
+const float z_ki_min = 0.0;
+const float z_ki_max = 0.5;
+
+const float x_winkel_min = -45.0;                // Winkelbegrenzung für X/Y/Z-Achse
+const float x_winkel_max =  45.0;
+const float y_winkel_min = -45.0;
+const float y_winkel_max =  45.0;
+const float z_winkel_min = -90.0;
+const float z_winkel_max =  90.0;
+
+const float regelgenauigkeit = 1.5;              // Regelgenauigkeit in Grad
+                                                 
+const float x_kp_def = 1.0;                      // DEFAULT REGELPARAMETER FÜR X/Y/Z-ACHSE
+const float x_kd_def = 0.4;
+const float x_ki_def = 0.01;
+const float y_kp_def = 1.0; 
+const float y_kd_def = 0.4;
+const float y_ki_def = 0.01;
+const float z_kp_def = 1.0; 
+const float z_kd_def = 0.4;
+const float z_ki_def = 0.01;
+
+DigitalOut uart_activity(LED1);                  // LED1 = UM6 SERIAL für Kommunikation
+       
+                                                                   
+/// FUNKTIONEN ////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// rxCallback // FUNKTION FÜR INTERRUPT - ABFRAGE DER DATEN DIE UM6-LT SENDET
+
+void rxCallback(MODSERIAL_IRQ_INFO *q) 
+{
+    if (um6_uart.rxBufferGetCount() >=  MAX_PACKET_DATA) 
+    {
+        uart_activity = !uart_activity;          // LED leuchtet wenn RxBuff hat > 40 Bytes
+        Process_um6_packet();
+    }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// calcStellwert // FUNKTION ZUR STELLWERTBERECHNUNG FÜR MBED-PWM
+
+float calcStellwert(float leistung) 
+{                                
+    return (startpw + ((leistung + 100) * pwmfakt)) / pulsweite;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// print_gyro_data // FUNKTION ZUR AUSGABE DER AKTUELLEN WINKEL UND WINKELGESCHWINDIGKEITEN
+
+void print_gyro_data()
+{                                              
+    ios.printf("Gyro_Proc_X     %+6.1f deg/s\n", data.Gyro_Proc_X);
+    ios.printf("Gyro_Proc_Y     %+6.1f deg/s\n", data.Gyro_Proc_Y);
+    ios.printf("Gyro_Proc_Z     %+6.1f deg/s\n", data.Gyro_Proc_Z);
+    ios.printf("Roll            %+6.1f deg\n", data.Roll);
+    ios.printf("Pitch           %+6.1f deg\n", data.Pitch);
+    ios.printf("Yaw             %+6.1f deg\n\n", data.Yaw);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// print_gyro_angles // FUNKTION ZUR AUSGABE DER AKTUELLEN WINKEL
+
+void print_gyro_angles()
+{                                            
+    ios.printf("Roll            %+6.1f deg\n", data.Roll);
+    ios.printf("Pitch           %+6.1f deg\n", data.Pitch);
+    ios.printf("Yaw             %+6.1f deg\n\n", data.Yaw);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// LageregelungAchse // FUNKTION ZUR LAGEREGELUNG FÜR EINE ACHSE - STATISCH - PD Regler
+
+void LageregelungAchse(float kp, float kd, float winkel, const float& gyro_veloc, 
+                       const float& gyro_angle, PwmOut& kreisel)
+{                   
+    float start_angle = gyro_angle;
+    float winkel_soll = gyro_angle + winkel;                                                      
+    float abweichung = gyro_angle - winkel_soll;
+    float leistung_alt = 0;                           // Variablen für Bremsverfahren
+    bool start = true;
+    
+    while (fabs(abweichung) > regelgenauigkeit) 
+    {
+        float leistung = abweichung * kp - gyro_veloc * kd;
+        if (leistung > max_leistung) leistung = max_leistung;
+        if (leistung < -max_leistung) leistung = -max_leistung;
+        if (leistung > -min_leistung && leistung < -0.001) leistung = -min_leistung;
+        if (leistung < min_leistung && leistung > 0.001) leistung = min_leistung;
+         
+        int Bremsrichtung = 0;                        // Vorzeichenbestimmung der Abbremsrichtung
+         
+        if (leistung >= 0)
+            Bremsrichtung = -1;
+        else 
+            Bremsrichtung = 1;
+        
+        float Stellwert = calcStellwert(leistung);    // Berechnung Stellwert
+        kreisel.write(Stellwert);                     // Befehl an Motorregler über PWM
+        wait_ms(20);
+        abweichung = gyro_angle - winkel_soll;        // Kontrolle der Regelgenauigkeit
+        
+        if (start == true) 
+        {                                             
+            leistung_alt = leistung;
+            start = false;
+        }      
+        else 
+        {
+            if (fabs(winkel) > 5.0) 
+            {                                     
+                if ( fabs(leistung) > min_leistung) 
+                { 
+                    float delta_leistung = fabs(leistung) - fabs(leistung_alt);     // Bestimmung Abfall Delta
+                    if (delta_leistung < -0.001) 
+                    {                                 // Abbremsung des Motors bei Leistungsabnahme
+                        kreisel.write(calcStellwert(Bremsrichtung * min_leistung)); 
+                        wait_ms(10);
+                    }
+                }
+            }
+            
+            leistung_alt = leistung;
+        }                                                       // Ende des Bremsverfahrens
+        
+        if (fabs(abweichung) <= regelgenauigkeit) 
+        {             // Vorzeichen für Bremsung wird bestimmt
+            print_gyro_data();                                  // Funktionsaufruf Gyrodaten ausgeben 
+            kreisel.write(calcStellwert(Bremsrichtung * 100));  // Vollbremsung
+            wait_ms(650); 
+            kreisel.write(calcStellwert(0));                    // Motor aus
+        }
+    }
+       
+    float end_angle = gyro_angle;        
+    ios.printf("Plattform wurde gedreht um %+6.1f deg\n\n", end_angle - start_angle);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// LageregelungAchseDyn // FUNKTION ZUR LAGEREGELUNG FÜR EINE ACHSE - DYNAMISCH - PID Regler
+
+void LageregelungAchseDyn(float kp, float kd, float ki, float winkel, const float& gyro_veloc, 
+                          const float& gyro_angle, PwmOut& kreisel, float& dyn_leistung_leerlauf)
+{                   
+    
+    ios.printf("Start LageregelungAchseDyn\n");
+    float start_angle = gyro_angle;
+    float winkel_soll = gyro_angle + winkel;
+    float abweichung = gyro_angle - winkel_soll;
+    float abweichung_sum = abweichung;
+    float leistung_alt = dyn_leistung_leerlauf;
+    bool  start = true;
+    float leistung = 0.0;
+    float i_glied = 0.0;
+    
+    int cnt = 0; 
+    while (fabs(abweichung) > regelgenauigkeit) 
+    {
+        cnt += 1;
+        i_glied = abweichung_sum * 0.001 * ki;
+        ios.printf("%f\n", i_glied);
+        if (i_glied > 0.5) i_glied = 0.5;                       // I-Glied Limiter 
+        if (i_glied < -0.5) i_glied = -0.5;
+        // Sumierstelle (PID Glieder)
+        leistung = dyn_leistung_leerlauf + abweichung * kp - gyro_veloc * kd + i_glied;            
+        if (leistung > max_leistung) leistung = max_leistung;
+        if (leistung < min_leistung) leistung = min_leistung;
+        int Bremsrichtung = -1;                                 // Vorzeichen der Abbremsrichtung 
+
+        float Stellwert = calcStellwert(leistung);              // Berechnung Stellwert
+        kreisel.write(Stellwert);                               // Befehl an Motorregler über Pwm
+        wait_ms(10);       
+    
+        if (start == true) 
+        {                                   
+            leistung_alt = leistung;
+            start = false;
+        }     
+        /*else 
+        {                       
+            if (leistung > min_leistung) 
+            { 
+                float delta_leistung = leistung - leistung_alt; // Bestimmung Abfall Delta
+                
+                // bei Abnahme der Leistung - Motor abbremsen
+                if (delta_leistung < -0.0001) 
+                {                 
+                    kreisel.write(calcStellwert(Bremsrichtung * min_leistung)); 
+                    wait_ms(5);
+                }
+            }
+        }
+        */
+        leistung_alt = leistung;
+        abweichung = gyro_angle - winkel_soll;
+        abweichung_sum += abweichung;
+    }
+    
+    dyn_leistung_leerlauf = leistung - i_glied;
+    if (dyn_leistung_leerlauf < min_leistung) dyn_leistung_leerlauf = min_leistung;
+    if (dyn_leistung_leerlauf > max_leistung) dyn_leistung_leerlauf = max_leistung;
+    ios.printf("Leerlaufleistung: %f\n", dyn_leistung_leerlauf);  
+    float end_angle = gyro_angle;      
+    ios.printf("Plattform wurde gedreht um %+6.1f deg\n\n", end_angle - start_angle);
+    // Counter für durchlaufene Regelzyklen             
+    ios.printf("\nEnde LageregelungAchseDyn; Counter: %i\n\n", cnt);                               
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// main // Hauptprogramm
+
+int main() 
+{                                                          
+    ios.baud(115200);                                                // Baudrate XBee Funkmodul
+    um6_uart.baud(115200);                                           // Baudrate UM6-lt 
+    um6_uart.attach(&rxCallback, MODSERIAL::RxIrq);                  // Interrupt Funktion für UART
+
+    rst = 1;                                                         // Reset-Pin von XBee auf ON
+    
+    ios.printf("\nBitte warten, Startvorgang der Plattform...\n\n"); // Start-UP Prozedur 
+    um6_uart.putc(0xAC);                                             // Nulliert die Rate-Gyros
+    wait_ms(3500);
+    um6_uart.putc(0xAC);                                             // Nulliert die Rate-Gyros
+    wait_ms(3500);
+    um6_uart.putc(0xAC);                                             // Nulliert die Rate-Gyros
+    wait_ms(3500);
+
+    x_kreisel.period_ms(pulsweite);                                 
+    y_kreisel.period_ms(pulsweite);
+    z_kreisel.period_ms(pulsweite);
+    
+    ios.printf("\n\nTESTPLATTFORM ZUR SATELLITENLAGEREGELUNG MIT REAKTIONSKREISELN:\n\n");
+         
+    int choice1 = 0;
+    
+    do 
+    {
+        do 
+        {
+            ios.printf("\n\nBitte folgende Anweisungen ausfuehren,falls nicht bereits erfolgt!\n"
+               "Stromversorgung der Testplattform trennen und ohne Druckluft mit X-Achse auf mag."
+               " Norden ausrichten.\n"
+               "Testplattform mit Wasserwaage horizontal tarieren.\n"
+               "Danach Stromversorgung herstellen und mbed Reset-Taste betaetigen.\n\n");
+            
+            x_kreisel.write(calcStellwert(0));                       //Initialisierung X-Motorrelger 
+            y_kreisel.write(calcStellwert(0));                       //Initialisierung Y-Motorrelger
+            z_kreisel.write(calcStellwert(0));                       //Initialisierung Z-Motorrelger
+            
+            ios.printf("Menueauswahl:\n");                          
+            ios.printf("\t1 - Testplattform um einzelne Achsen drehen\n");
+            ios.printf("\t2 - Testplattform um drei Achsen drehen\n");
+            ios.printf("\t3 - Lage der Testplattform aktiv regeln fuer dynamische Fehler\n");
+            ios.printf("\t4 - Gyrodaten ausgeben [Winkel/Winkelgeschwindigkeiten]\n");
+            ios.printf("\t5 - Programm beenden\n");
+            ios.printf("\nEingabe >");
+            ios.scanf("%i", &choice1);
+        }while (choice1 < 1 || choice1 > 5);
+        
+        if (choice1 == 1)
+        { 
+            ios.printf("\nTestplattform ist initialisiert.\n\n");
+            print_gyro_angles();                                     // Funktionsaufruf Gyrodwinkel ausgeben     
+            float x_kp = x_kp_def;
+            float x_kd = x_kd_def;
+            float x_winkel = 0.0;
+            float y_kp = y_kp_def; 
+            float y_kd = y_kd_def;
+            float y_winkel = 0.0;
+            float z_kp = z_kp_def; 
+            float z_kd = z_kd_def;
+            float z_winkel = 0.0;
+
+            int choice2 = 0;
+            
+            do 
+            {
+                do 
+                {
+                    ios.printf("\n\nLAGEREGELUNG EINZELNER ACHSEN:\n\n");                         
+                    ios.printf("Menueauswahl:\n");
+                    ios.printf("\t1 - Satellitenplattform rollen (um X-Achse drehen)\n");
+                    ios.printf("\t2 - Satellitenplattform nicken (um Y-Achse drehen)\n");
+                    ios.printf("\t3 - Satellitenplattform gieren (um Z-Achse drehen)\n");
+                    ios.printf("\t4 - Auswahl abbrechen (esc).\n");
+                    ios.printf("\nEingabe >");
+                    ios.scanf("%i", &choice2); 
+                }while (choice2 < 1 || choice2 > 4);
+
+                if (choice2 == 1)
+                {
+                    ios.printf("\n Reglerparameter kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &x_kp);          
+                    if (x_kp > x_kp_max) x_kp = x_kp_max;                 // Begrenzung X-Achse kp Pos.
+                    if (x_kp < x_kp_min) x_kp = x_kp_min;                 // Begrenzung X-Achse kp Neg.
+                    ios.printf("\n Reglerparameter kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &x_kd); 
+                    if (x_kd > x_kd_max) x_kd = x_kd_max;                 // Begrenzung X-Achse kd Pos.
+                    if (x_kd < x_kd_min) x_kd = x_kd_min;                 // Begrenzung X-Achse kd Neg.      
+                    ios.printf("\n Rollwinkel Phi eingeben [-45 - +45] >");
+                    ios.scanf("%f", &x_winkel);
+                    if (x_winkel > x_winkel_max) x_winkel = x_winkel_max; // Begrenzung X-Achse Winkel Pos.
+                    if (x_winkel < x_winkel_min) x_winkel = x_winkel_min; // Begrenzung X-Achse Winkel Neg.   
+                    if (fabs(x_winkel) < regelgenauigkeit) ios.printf("\nRegelung ist nicht notwendig!");
+                    ios.printf("\nParameter kp = %f, Parameter kd = %f, Rollwinkel = %f\n", 
+                               x_kp, x_kd, x_winkel); 
+                    print_gyro_angles();
+                    LageregelungAchse(x_kp, x_kd, x_winkel, data.Gyro_Proc_X, data.Roll, x_kreisel);
+                }
+                else if (choice2 == 2) 
+                {
+                    ios.printf("\n Reglerparameter kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &y_kp);
+                    if (y_kp > y_kp_max) y_kp = y_kp_max;                 // Begrenzung Y-Achse kp Pos.
+                    if (y_kp < y_kp_min) y_kp = y_kp_min;                 // Begrenzung Y-Achse kp Neg.
+                    ios.printf("\n Reglerparameter kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &y_kd);
+                    if (y_kd > y_kd_max) y_kd = y_kd_max;                 // Begrenzung Y-Achse kd Pos.
+                    if (y_kd < y_kd_min) y_kd = y_kd_min;                 // Begrenzung Y-Achse kd Neg.
+                    ios.printf("\n Nickwinkel Theta eingeben [-45 - +45] >");
+                    ios.scanf("%f", &y_winkel);                             
+                    if (y_winkel > y_winkel_max) y_winkel = y_winkel_max; // Begrenzung Y-Achse Winkel Pos.
+                    if (y_winkel < y_winkel_min) y_winkel = y_winkel_min; // Begrenzung Y-Achse Winkel Neg.   
+                    if (fabs(y_winkel) < regelgenauigkeit) ios.printf("\nRegelung ist nicht notwendig!");
+                    ios.printf("\nParameter kp = %f, Parameter kd = %f, Nickwinkel = %f\n", 
+                                y_kp, y_kd, y_winkel); 
+                    print_gyro_angles();                                                  
+                    LageregelungAchse(y_kp, y_kd, y_winkel, data.Gyro_Proc_Y, data.Pitch, y_kreisel);
+                                     
+                 } 
+                 else if (choice2 == 3) 
+                 {                    
+                    ios.printf("\n Reglerparameter kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &z_kp);
+                    if (z_kp > z_kp_max) z_kp = z_kp_max;                 // Begrenzung Z-Achse kp Pos.
+                    if (z_kp < z_kp_min) z_kp = z_kp_min;                 // Begrenzung Z-Achse kp Neg.
+                    ios.printf("\n Reglerparameter kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &z_kd);
+                    if (z_kd > z_kd_max) z_kd = z_kd_max;                 // Begrenzung Z-Achse kd Pos.
+                    if (z_kd < z_kd_min) z_kd = z_kd_min;                 // Begrenzung Z-Achse kd Neg.   
+                    ios.printf("\n Gierwinkel Psi eingeben [-90 - +90] >");
+                    ios.scanf("%f", &z_winkel);      
+                    if (z_winkel > z_winkel_max) z_winkel = z_winkel_max; // Begrenzung Z-Achse Winkel Pos.
+                    if (z_winkel < z_winkel_min) z_winkel = z_winkel_min; // Begrenzung Z-Achse Winkel Neg.   
+                    if (fabs(z_winkel) < regelgenauigkeit) ios.printf("\nRegelung ist nicht notwendig!");
+                    ios.printf("\nParameter kp = %f, Parameter kd = %f, Gierwinkel = %f\n", 
+                                z_kp, z_kd, z_winkel); 
+                    print_gyro_angles();
+                    LageregelungAchse(z_kp, z_kd, z_winkel, data.Gyro_Proc_Z, data.Yaw, z_kreisel);
+                }
+            }while(choice2 != 4);
+            
+        }
+        else if (choice1 == 2)
+        {
+            float x_kp = x_kp_def;
+            float x_kd = x_kd_def;
+            float x_winkel = 0.0;
+            float y_kp = y_kp_def; 
+            float y_kd = y_kd_def;
+            float y_winkel = 0.0;
+            float z_kp = z_kp_def; 
+            float z_kd = z_kd_def;
+            float z_winkel = 0.0;
+       
+            int choice3 = 0;
+            
+            do 
+            {
+                do 
+                {
+                    ios.printf("\n\nLAGEREGELUNG ALLER ACHSEN:\n\n");
+                    ios.printf("Bitte Plattform in gewuenschte Ausgangsposition bringen.\n");
+                    ios.printf("Plattform wird in Z-Y-X Reihenfolge gedreht!\n\n");
+                    ios.printf("Aktuelle Werte fuer Regler X-Achse: kp = %f kd = %f\n\n", x_kp, x_kd);
+                    ios.printf("Aktuelle Werte fuer Regler Y-Achse: kp = %f kd = %f\n\n", y_kp, y_kd);
+                    ios.printf("Aktuelle Werte fuer Regler Z-Achse: kp = %f kd = %f\n\n", z_kp, z_kd);
+                    ios.printf("Menueauswahl:\n");
+                    ios.printf("\t1 - Regelparameter aendern?\n");
+                    ios.printf("\t2 - Plattform drehen-Winkel eingeben\n");
+                    ios.printf("\t3 - Auswahl abbrechen (esc).\n");
+                    ios.printf("\nEingabe >");
+                    ios.scanf("%i", &choice3); 
+                }while (choice3 < 1 || choice3 > 3);
+                      
+                if (choice3 == 1)
+                {
+                    ios.printf("\n Reglerparameter x_kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &x_kp);          
+                    if (x_kp > x_kp_max) x_kp = x_kp_max;                 // Begrenzung X-Achse kp Pos.
+                    if (x_kp < x_kp_min) x_kp = x_kp_min;                 // Begrenzung X-Achse kp Neg.
+                    ios.printf("\n Reglerparameter x_kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &x_kd); 
+                    if (x_kd > x_kd_max) x_kd = x_kd_max;                 // Begrenzung X-Achse kd Pos.
+                    if (x_kd < x_kd_min) x_kd = x_kd_min;                 // Begrenzung X-Achse kd Neg.
+                    ios.printf("\n Reglerparameter y_kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &y_kp);
+                    if (y_kp > y_kp_max) y_kp = y_kp_max;                 // Begrenzung Y-Achse kp Pos.
+                    if (y_kp < y_kp_min) y_kp = y_kp_min;                 // Begrenzung Y-Achse kp Neg.
+                    ios.printf("\n Reglerparameter y_kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &y_kd);
+                    if (y_kd > y_kd_max) y_kd = y_kd_max;                 // Begrenzung Y-Achse kd Pos.
+                    if (y_kd < y_kd_min) y_kd = y_kd_min;                 // Begrenzung Y-Achse kd Neg.
+                    ios.printf("\n Reglerparameter z_kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &z_kp);
+                    if (z_kp > z_kp_max) z_kp = z_kp_max;                 // Begrenzung Z-Achse kp Pos.
+                    if (z_kp < z_kp_min) z_kp = z_kp_min;                 // Begrenzung Z-Achse kp Neg.
+                    ios.printf("\n Reglerparameter z_kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &z_kd);
+                    if (z_kd > z_kd_max) z_kd = z_kd_max;                 // Begrenzung Z-Achse kd Pos.
+                    if (z_kd < z_kd_min) z_kd = z_kd_min;                 // Begrenzung Z-Achse kd Neg. 
+                    ios.printf("\n\n"); 
+                    ios.printf("Aktuelle Werte fuer Regler X-Achse: kp = %f kd = %f\n\n", x_kp, x_kd);
+                    ios.printf("Aktuelle Werte fuer Regler Y-Achse: kp = %f kd = %f\n\n", y_kp, y_kd);
+                    ios.printf("Aktuelle Werte fuer Regler Z-Achse: kp = %f kd = %f\n\n", z_kp, z_kd);
+                }
+                else if (choice3 == 2)
+                {                                                         // Eingabe der Drehwinkel
+                    ios.printf("\n Gierwinkel Psi eingeben [-90 - +90] >");
+                    ios.scanf("%f", &z_winkel);      
+                    if (z_winkel > z_winkel_max) z_winkel = z_winkel_max; // Begrenzung Z-Achse Winkel Pos.
+                    if (z_winkel < z_winkel_min) z_winkel = z_winkel_min; // Begrenzung Z-Achse Winkel Neg.
+                    ios.printf("\n Nickwinkel Theta eingeben [-45 - +45] >");
+                    ios.scanf("%f", &y_winkel);                             
+                    if (y_winkel > y_winkel_max) y_winkel = y_winkel_max; // Begrenzung Y-Achse Winkel Pos.
+                    if (y_winkel < y_winkel_min) y_winkel = y_winkel_min; // Begrenzung Y-Achse Winkel Neg.
+                    ios.printf("\n Rollwinkel Phi eingeben [-45 - +45] >");
+                    ios.scanf("%f", &x_winkel);
+                    if (x_winkel > x_winkel_max) x_winkel = x_winkel_max; // Begrenzung X-Achse Winkel Pos.
+                    if (x_winkel < x_winkel_min) x_winkel = x_winkel_min; // Begrenzung X-Achse Winkel Neg.
+                        
+                    if (fabs(z_winkel) < regelgenauigkeit && 
+                        fabs(y_winkel) < regelgenauigkeit && 
+                        fabs(x_winkel) < regelgenauigkeit)
+                    {
+                        ios.printf("\nRegelung ist nicht notwendig!");
+                    }
+                    else 
+                    {
+                        print_gyro_angles();
+                        LageregelungAchse(z_kp, z_kd, z_winkel, data.Gyro_Proc_Z, data.Yaw, z_kreisel);
+                        wait_ms(250);   
+                        LageregelungAchse(y_kp, y_kd, y_winkel, data.Gyro_Proc_Y, data.Pitch, y_kreisel);
+                        wait_ms(250);
+                        LageregelungAchse(x_kp, x_kd, x_winkel, data.Gyro_Proc_X, data.Roll, x_kreisel);
+                        print_gyro_angles();
+                        ios.printf("\n\nSoll die Plattform wieder in ihre Ausgangslage gefahren werden? "
+                                   "ja/nein\n");
+                        char yes_no[50]; 
+                        ios.scanf("%s", yes_no);
+                        
+                        if (strcmp(yes_no, "ja") == 0)    // Plattform in auf Ausgangsposition drehen
+                        {                       
+                            LageregelungAchse(x_kp, x_kd, -x_winkel, data.Gyro_Proc_X, data.Roll, x_kreisel);
+                            wait_ms(250);  
+                            LageregelungAchse(y_kp, y_kd, -y_winkel, data.Gyro_Proc_Y, data.Pitch, y_kreisel);
+                            wait_ms(250);
+                            LageregelungAchse(z_kp, z_kd, -z_winkel, data.Gyro_Proc_Z, data.Yaw, z_kreisel);
+                            print_gyro_angles();
+                        }
+                    }
+                }  
+                            
+            }while(choice3 != 3);
+        }
+        else if (choice1 == 3)
+        {
+            float x_kp = x_kp_def;
+            float x_kd = x_kd_def;
+            float x_ki = x_ki_def;
+            float y_kp = y_kp_def; 
+            float y_kd = y_kd_def;
+            float y_ki = y_ki_def;
+            float z_kp = z_kp_def; 
+            float z_kd = z_kd_def;
+            float z_ki = z_ki_def;
+       
+            int choice4 = 0;
+            
+            do 
+            {
+                do 
+                {
+                    ios.printf("\n\nLage der Testplattform aktiv regeln fuer dynamische Fehler"
+                               " (Position halten):\n\n");
+                    ios.printf("\n\nBitte Plattform in gewuenschte Ausgangsposition bringen und halten "
+                               "bis die Kreisel "
+                               "ihre Leerlaufdrehzahl erreicht haben.\n\n");
+                    ios.printf("Aktuelle Werte fuer Regler X-Achse: kp = %f kd = %f ki = %f\n", 
+                                x_kp, x_kd, x_ki); 
+                    ios.printf("Aktuelle Werte fuer Regler Y-Achse: kp = %f kd = %f ki = %f\n", 
+                                y_kp, y_kd, y_ki);
+                    ios.printf("Aktuelle Werte fuer Regler Z-Achse: kp = %f kd = %f ki = %f\n\n", 
+                                z_kp, z_kd, z_ki);
+                    ios.printf("Menueauswahl:\n");
+                    ios.printf("\t1 - Regelparameter aendern?\n");
+                    ios.printf("\t2 - Plattform aktivieren\n");
+                    ios.printf("\t3 - Auswahl abbrechen (esc).\n");
+                    ios.printf("\nEingabe >");
+                    ios.scanf("%i", &choice4); 
+                }while (choice4 < 1 || choice4 > 3);  
+                       
+                if (choice4 == 1)
+                {
+                    /*
+                    ios.printf("\n Reglerparameter x_kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &x_kp);          
+                    if (x_kp > x_kp_max) x_kp = x_kp_max;                 // Begrenzung X-Achse kp Pos.
+                    if (x_kp < x_kp_min) x_kp = x_kp_min;                 // Begrenzung X-Achse kp Neg.
+                    ios.printf("\n Reglerparameter x_kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &x_kd); 
+                    if (x_kd > x_kd_max) x_kd = x_kd_max;                 // Begrenzung X-Achse kd Pos.
+                    if (x_kd < x_kd_min) x_kd = x_kd_min;                 // Begrenzung X-Achse kd Neg.
+                    ios.printf("\n Reglerparameter x_ki eingeben [0 - +0.5] >");
+                    ios.scanf("%f", &x_ki); 
+                    if (x_ki > x_ki_max) x_ki = x_ki_max;                 // Begrenzung X-Achse ki Pos.
+                    if (x_ki < x_ki_min) x_ki = x_ki_min;                 // Begrenzung X-Achse ki Neg.
+                    ios.printf("\n Reglerparameter y_kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &y_kp);
+                    if (y_kp > y_kp_max) y_kp = y_kp_max;                 // Begrenzung Y-Achse kp Pos.
+                    if (y_kp < y_kp_min) y_kp = y_kp_min;                 // Begrenzung Y-Achse kp Neg.
+                    ios.printf("\n Reglerparameter y_kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &y_kd);
+                    if (y_kd > y_kd_max) y_kd = y_kd_max;                 // Begrenzung Y-Achse kd Pos.
+                    if (y_kd < y_kd_min) y_kd = y_kd_min;                 // Begrenzung Y-Achse kd Neg.
+                    ios.printf("\n Reglerparameter y_ki eingeben [0 - +0.5] >");
+                    ios.scanf("%f", &y_ki); 
+                    if (y_ki > y_ki_max) y_ki = y_ki_max;                 // Begrenzung Y-Achse ki Pos.
+                    if (y_ki < y_ki_min) y_ki = y_ki_min;                 // Begrenzung Y-Achse ki Neg.
+                    */  
+                    ios.printf("\n Reglerparameter z_kp eingeben [0 - +3] >");
+                    ios.scanf("%f", &z_kp);
+                    if (z_kp > z_kp_max) z_kp = z_kp_max;                 // Begrenzung Z-Achse kp Pos.
+                    if (z_kp < z_kp_min) z_kp = z_kp_min;                 // Begrenzung Z-Achse kp Neg.
+                    ios.printf("\n Reglerparameter z_kd eingeben [0 - +3] >");
+                    ios.scanf("%f", &z_kd);
+                    if (z_kd > z_kd_max) z_kd = z_kd_max;                 // Begrenzung Z-Achse kd Pos.
+                    if (z_kd < z_kd_min) z_kd = z_kd_min;                 // Begrenzung Z-Achse kd Neg. 
+                    ios.printf("\n Reglerparameter z_ki eingeben [0 - +0.5] >");
+                    ios.scanf("%f", &z_ki); 
+                    if (z_ki > z_ki_max) z_ki = z_ki_max;                 // Begrenzung Z-Achse ki Pos.
+                    if (z_ki < z_ki_min) z_ki = z_ki_min;                 // Begrenzung Z-Achse ki Neg.
+                    ios.printf("\n\n"); 
+                    //ios.printf("Aktuelle Werte fuer Regler X-Achse: kp = %f kd = %f ki = %f\n\n", 
+                    //            x_kp, x_kd, x_ki); 
+                    //ios.printf("Aktuelle Werte fuer Regler Y-Achse: kp = %f kd = %f ki = %f\n\n", 
+                    //            y_kp, y_kd, y_ki);
+                    ios.printf("Aktuelle Werte fuer Regler Z-Achse: kp = %f kd = %f ki = %f\n\n", 
+                                z_kp, z_kd, z_ki);
+                }
+                else if (choice4 == 2)
+                {                                       
+                    ios.printf("\n\nUm abzubrechen bitte Reset-Taste an mbed betaetigen!\n\n");
+                    float ziel_x_winkel = data.Roll;
+                    float ziel_y_winkel = data.Pitch;
+                    float ziel_z_winkel = data.Yaw;
+                    
+                    print_gyro_angles();                                 
+                    float x_dyn_leistung_leerlauf = (min_leistung + max_leistung)/2; // Leistung im Leerlauf 
+                    float y_dyn_leistung_leerlauf = (min_leistung + max_leistung)/2; // Leistung im Leerlauf 
+                    float z_dyn_leistung_leerlauf = (min_leistung + max_leistung)/2; // Leistung im Leerlauf
+                    
+                    wait_ms(2000);
+                    z_kreisel.write(calcStellwert(z_dyn_leistung_leerlauf));
+                    //y_kreisel.write(calcStellwert(y_dyn_leistung_leerlauf));
+                    //x_kreisel.write(calcStellwert(x_dyn_leistung_leerlauf));
+            
+                    while(1)
+                    {
+                        while (fabs(ziel_z_winkel - data.Yaw) > regelgenauigkeit)
+                        {     
+                            LageregelungAchseDyn(z_kp, z_kd, z_ki, ziel_z_winkel - data.Yaw, data.Gyro_Proc_Z, 
+                                                 data.Yaw, z_kreisel, z_dyn_leistung_leerlauf);
+                        }
+                        
+                        /*
+                        while (fabs(ziel_y_winkel - data.Pitch) > regelgenauigkeit)
+                        {  
+                            LageregelungAchseDyn(y_kp, y_kd, y_ki, ziel_y_winkel - data.Roll, data.Gyro_Proc_Y, 
+                                                 data.Pitch, y_kreisel, y_dyn_leistung_leerlauf);  
+                        }
+                        
+                        while (fabs(ziel_x_winkel - data.Roll) > regelgenauigkeit)
+                        {
+                            LageregelungAchseDyn(x_kp, x_kd, x_ki, ziel_x_winkel - data.Pitch, data.Gyro_Proc_X, 
+                                                 data.Roll, x_kreisel, x_dyn_leistung_leerlauf);
+                        }
+                        */
+                    }
+                }
+            }while(choice4 != 3);
+        }
+        else if (choice1 == 4)
+        { 
+            print_gyro_data();
+        }
+          
+    }while(choice1 != 5); 
+ 
+    ios.printf("\n\nProgramm beendet.\n");
+}
\ No newline at end of file
diff -r 000000000000 -r 1447d2f773db mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Jul 09 07:35:50 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/a9913a65894f
\ No newline at end of file