BeaconAvoid code for AHRC competition.

Dependencies:   MODSERIAL PiSlingers m3pi mbed

Files at this revision

API Documentation at this revision

Comitter:
mpanetta
Date:
Wed Apr 04 17:07:49 2012 +0000
Child:
1:ac4eff391f12
Commit message:
Initial commit. Avoidance code complete, beacon code still needs to be added.

Changed in this revision

IRBehaviorController.cpp Show annotated file Show diff for this revision Revisions of this file
IRBehaviorController.h Show annotated file Show diff for this revision Revisions of this file
MODSERIAL/.lib Show annotated file Show diff for this revision Revisions of this file
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
PID.cpp Show annotated file Show diff for this revision Revisions of this file
PID.h Show annotated file Show diff for this revision Revisions of this file
PiSlingers/.lib Show annotated file Show diff for this revision Revisions of this file
PiSlingers/Beacon.cpp Show annotated file Show diff for this revision Revisions of this file
PiSlingers/Beacon.h Show annotated file Show diff for this revision Revisions of this file
PiSlingers/IRObjDetector.cpp Show annotated file Show diff for this revision Revisions of this file
PiSlingers/IRObjDetector.h Show annotated file Show diff for this revision Revisions of this file
PiSlingers/tlc5916.cpp Show annotated file Show diff for this revision Revisions of this file
PiSlingers/tlc5916.h Show annotated file Show diff for this revision Revisions of this file
m3pi/.lib Show annotated file Show diff for this revision Revisions of this file
m3pi/m3pi.cpp Show annotated file Show diff for this revision Revisions of this file
m3pi/m3pi.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.lib Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IRBehaviorController.cpp	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,99 @@
+#include "mbed.h"
+
+#include "IRBehaviorController.h"
+
+
+// Public methods
+
+void
+IRBehaviorController::setActiveThreshold(float threshold)
+{
+    NVIC_DisableIRQ(TIMER3_IRQn);   // Disable Ticker IRQ for atomicity
+    activationThreshold = threshold;
+    NVIC_EnableIRQ(TIMER3_IRQn);    // Enable Ticker IRQ
+}
+
+
+void
+IRBehaviorController::runSeeking(void)
+{
+    if (debug != NULL)
+        debug->printf("IRController: Seeking Task Start.\r\n");
+    
+    scanIR();
+
+    if (brightness > activationThreshold)
+        output = pid->run(centeroid);
+    else
+        output = 0;
+    
+    if (debug != NULL)
+        debug->printf("IRController: Seeking Task Complete.\r\n");
+}
+
+void
+IRBehaviorController::runAvoidance(void)
+{
+    if (debug != NULL)
+        debug->printf("IRController: Avoidance Task Start.\r\n");
+    
+    scanIR();
+
+    // Centeroid value needs to be split for avoidance mode.
+    if (centeroid < 0)
+        centeroid += 3;
+    else
+        centeroid -=3;
+        
+    if (brightness > activationThreshold)
+        output = pid->run(centeroid);    
+    else
+        output = 0;
+    
+    if (debug != NULL)
+        debug->printf("IRController: Avoidance Task Complete.\r\n");
+}
+
+float
+IRBehaviorController::getPower(void)
+{
+    float tmp;
+    
+    NVIC_DisableIRQ(TIMER3_IRQn);   // Disable Ticker IRQ for atomicity
+    tmp = output;
+    NVIC_EnableIRQ(TIMER3_IRQn);    // Enable Ticker IRQ
+    
+    return tmp;
+}
+
+void
+IRBehaviorController::dumpDebug(Serial *debug)
+{
+    if (debug != NULL)
+    {
+        debug->printf("IRController: Centeroid  = %3.2f\r\n", centeroid);
+        debug->printf("IRController: Brightness = %3.2f\r\n", brightness);
+        debug->printf("IRController: Power      = %3.2f\r\n", output);
+    }   
+}
+
+// Private methods
+
+void
+IRBehaviorController::scanIR(void)
+{
+    if (debug != NULL)
+        debug->printf("IRController: Scanning IR.\r\n");
+    
+    ird.scan();
+    
+    centeroid  = ird.get_centeroid();
+    brightness = ird.get_weighted_avg_brightness();
+    
+    if (debug != NULL)
+    {
+        debug->printf("IRController: Scan complete.\r\n");
+        debug->printf("IRController: Centeroid  = %3.2f\r\n", centeroid);
+        debug->printf("IRController: Brightness = %3.2f\r\n", brightness);
+    }   
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IRBehaviorController.h	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,54 @@
+#ifndef __IRBEHAVIORCONTROLLER_H__
+#define __IRBEHAVIORCONTROLLER_H__
+
+#include "mbed.h"
+#include "IRObjDetector.h"
+#include "PID.h"
+
+class IRBehaviorController
+{
+public:
+    IRBehaviorController(PID *pid) : pid(pid)
+    {
+        debug               = NULL;
+        activationThreshold = 0.0f;
+        brightness          = 0.0f;
+        output              = 0.0f;        
+    };
+    
+    IRBehaviorController(PID * pid, Serial * debug) : debug(debug), ird(debug), pid(pid)
+    //IRBehaviorController(PID * pid, Serial * debug) : debug(debug), pid(pid) 
+    {
+        activationThreshold = 0.0f;
+        brightness          = 0.0f;
+        output              = 0.0f;
+    };
+    
+    void setAvoidanceBehavior(float threshold);
+    void setSeekingBehavior(float threshold);
+    
+    void setActiveThreshold(float threshold);   // Brightness level at which behavior is active.
+    
+    void runAvoidance(void);                    // Execute avoidance behavior
+    void runSeeking(void);                      // Execute seeking behavior
+    
+    float getPower(void);                       // Returns the power value needed to execute the behavior.
+    
+    void  dumpDebug(Serial *debug);
+    
+private:
+
+    void            scanIR(void);
+
+    Serial          *debug;
+    
+    IRObjDetector   ird;
+    PID             *pid;
+    
+    float           activationThreshold;             // Brightness threshold at which behavior is active.
+    float           brightness;
+    float           centeroid;
+      
+    float           output;
+};
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/.lib	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/AjK/libraries/MODSERIAL/lqybn0
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/ChangeLog.c	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,153 @@
+/* $Id:$
+
+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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/FLUSH.cpp	Wed Apr 04 17:07:49 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/GETC.cpp	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,63 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+#include "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;
+    }
+    
+    buffer_count[RxIrq]--;   
+    return c;
+}
+
+}; // namespace AjK ends
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/INIT.cpp	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,74 @@
+/*
+    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);
+    
+    switch(_uidx) {
+        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;
+    }
+    
+    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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/ISR_RX.cpp	Wed Apr 04 17:07:49 2012 +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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/ISR_TX.cpp	Wed Apr 04 17:07:49 2012 +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
+
+        
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/MACROS.h	Wed Apr 04 17:07:49 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/MODSERIAL.cpp	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,128 @@
+/*
+    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)
+{
+    switch(_uidx) {
+        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;
+    }
+}
+
+void
+MODSERIAL::enableIrq(void)
+{
+    switch(_uidx) {
+        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;
+    }
+}
+
+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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/MODSERIAL.h	Wed Apr 04 17:07:49 2012 +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(_uidx) {
+            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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/MODSERIAL_IRQ_INFO.cpp	Wed Apr 04 17:07:49 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/PUTC.cpp	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,79 @@
+/*
+    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;
+        buffer_count[TxIrq]++;
+        buffer_in[TxIrq]++;
+        if (buffer_in[TxIrq] >= buffer_size[TxIrq]) {
+            buffer_in[TxIrq] = 0;
+        }            
+        _IER |= 2;        
+    }
+      
+    return 0;
+}
+
+}; // namespace AjK ends
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL/RESIZE.cpp	Wed Apr 04 17:07:49 2012 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PID.cpp	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,103 @@
+#include "PID.h"
+
+void
+PID::setP(float p)
+{
+    NVIC_DisableIRQ(TIMER3_IRQn);   // Disable Ticker IRQ for atomicity
+    k_p = p;
+    NVIC_EnableIRQ(TIMER3_IRQn);    // Enable Ticker IRQ
+}
+
+void
+PID::setI(float i)
+{
+    NVIC_DisableIRQ(TIMER3_IRQn);   // Disable Ticker IRQ for atomicity
+    k_i = i;
+    NVIC_EnableIRQ(TIMER3_IRQn);    // Enable Ticker IRQ
+}
+
+void 
+PID::setD(float d)
+{
+    NVIC_DisableIRQ(TIMER3_IRQn);   // Disable Ticker IRQ for atomicity
+    k_d = d;
+    NVIC_EnableIRQ(TIMER3_IRQn);    // Enable Ticker IRQ
+}
+
+void 
+PID::setClip(float clip)
+{
+    NVIC_DisableIRQ(TIMER3_IRQn);   // Disable Ticker IRQ for atomicity
+    this->clip = clip;
+    NVIC_EnableIRQ(TIMER3_IRQn);    // Enable Ticker IRQ
+}
+
+void
+PID::setPV(float pv) // Set process variable
+{
+    NVIC_DisableIRQ(TIMER3_IRQn);   // Disable Ticker IRQ for atomicity
+    error = pv;
+    NVIC_EnableIRQ(TIMER3_IRQn);    // Enable Ticker IRQ
+
+}
+
+void
+PID::dumpDebug(Serial *debug)
+{
+    if (debug != NULL)
+    {
+        debug->printf("PID Debug: v_p        = %3.2f\r\n", v_p);
+        debug->printf("PID Debug: v_i        = %3.2f\r\n", v_i);
+        debug->printf("PID Debug: v_d        = %3.2f\r\n", v_d);
+        debug->printf("PID Debug: k_p        = %3.2f\r\n", k_p);
+        debug->printf("PID Debug: k_i        = %3.2f\r\n", k_i);
+        debug->printf("PID Debug: k_d        = %3.2f\r\n", k_d);
+        debug->printf("PID Debug: clip       = %3.2f\r\n", clip);
+        debug->printf("PID Debug: error      = %3.2f\r\n", error);
+        debug->printf("PID Debug: prev_error = %3.2f\r\n", prev_error);
+        debug->printf("PID Debug: output     = %3.2f\r\n", output);
+    }
+}
+
+float
+PID::run(float in)
+{
+    if (debug != NULL)
+        debug->printf("PID Debug: in         = %3.2f\r\n", in);
+    error = in;
+    
+    v_p  = error;
+    v_i += v_p;
+    v_d  = error - prev_error;    
+    
+    if (v_i > clip)
+        v_i = clip;
+    if (v_i < clip)
+        v_i = -clip;
+    if (v_i != v_i) // NAN check...
+        v_i = 0;
+        
+    if (debug != NULL)
+    {
+        debug->printf("PID Debug: v_p        = %3.2f\r\n", v_p);
+        debug->printf("PID Debug: v_i        = %3.2f\r\n", v_i);
+        debug->printf("PID Debug: v_d        = %3.2f\r\n", v_d);
+        debug->printf("PID Debug: k_p        = %3.2f\r\n", k_p);
+        debug->printf("PID Debug: k_i        = %3.2f\r\n", k_i);
+        debug->printf("PID Debug: k_d        = %3.2f\r\n", k_d);
+        debug->printf("PID Debug: clip       = %3.2f\r\n", clip);
+    }
+    
+    output = (v_p * k_p) + (v_i * k_i) + (v_d * k_d);
+    
+    if (debug != NULL)
+    {
+        debug->printf("PID Debug: error      = %3.2f\r\n", error);
+        debug->printf("PID Debug: prev_error = %3.2f\r\n", prev_error);
+        debug->printf("PID Debug: output     = %3.2f\r\n", output);
+    }
+    
+    prev_error = error;
+    
+    return output;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PID.h	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,59 @@
+#ifndef __PID_H__
+#define __PID_H__
+
+#include "mbed.h"
+
+class PID
+{
+public:
+    PID(float i_p, float i_i, float i_d) : 
+        k_p(i_p), k_i(i_i), k_d(i_d)
+        {
+            debug      = NULL;
+            
+            v_p        = 0.0f;
+            v_i        = 0.0f;
+            v_d        = 0.0f;
+            
+            clip       = 1.0f;
+            error      = 0.0f;
+            prev_error = 0.0f;
+        }
+
+    PID(float i_p, float i_i, float i_d, Serial *debug) : 
+        debug(debug), k_p(i_p), k_i(i_i), k_d(i_d)
+        {
+            v_p        = 0.0f;
+            v_i        = 0.0f;
+            v_d        = 0.0f;
+            
+            clip       = 1.0f;
+            error      = 0.0f;
+            prev_error = 0.0f;
+        }
+        
+    void  setP(float p);       // set k_p
+    void  setI(float i);       // set k_i
+    void  setD(float d);       // set k_d
+    void  setClip(float clip);
+    void  setPV(float pv);     // Set process variable (PID input)
+    float getOutput(void);     // Get PID output.
+    
+    void  run(void);           // Callback to be called via Ticker to execute the PID algo.
+    float run(float in);       // Version to run PID in place (not via timer or interrupt)
+    
+    void dumpDebug(Serial *debug);    
+    
+private:
+    Serial *debug;
+
+    float k_p, k_i, k_d; // PID constants
+    float v_p, v_i, v_d; // PID variables
+    float clip;   // Integral clip value (absolute)
+    float error;
+    float prev_error;
+    float output;
+
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PiSlingers/.lib	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,1 @@
+ 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PiSlingers/Beacon.cpp	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,49 @@
+#include "Beacon.h"
+
+void
+Beacon::scan(void)
+{
+    valL = ainL.read_u16() >> 8;
+    valR = ainR.read_u16() >> 8;
+//    valR = ainL.read_u16() >> 8;
+//    valL = ainR.read_u16() >> 8;
+    
+    valL > valR ?  max = valL : max = valR;
+    
+    calc_centeroid();
+}
+
+void
+Beacon::calc_centeroid(void)
+{
+    float sumA, sumB;
+    
+    sumB = (valL * 1) + (valR * 2);
+    sumA = valL + valR;
+    
+    centeroid = sumB / sumA - 1.5f;
+}
+
+float
+Beacon::get_centeroid(void)
+{
+    return centeroid;
+}
+
+uint8_t
+Beacon::get_max_rssi(void)
+{
+    return max;
+}
+
+uint8_t
+Beacon::getL(void)
+{
+    return valL;
+}
+
+uint8_t
+Beacon::getR(void)
+{
+    return valR;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PiSlingers/Beacon.h	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,32 @@
+#ifndef _BEACON_H_
+#define _BEACON_H_
+
+#include "mbed.h"
+
+class Beacon 
+{
+public:
+    Beacon(void) : ainL(p19), ainR(p20) {};
+    
+    void    scan(void);
+    uint8_t get_max_rssi(void);
+    float   get_centeroid(void);
+    
+    uint8_t getL(void);
+    uint8_t getR(void);
+    
+private:
+    void calc_centeroid(void);
+
+    AnalogIn ainL;
+    AnalogIn ainR;
+    
+    uint8_t  valL;
+    uint8_t  valR;
+    
+    uint8_t  max;
+    float    centeroid;
+
+};
+
+#endif //_BEACON_H_
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PiSlingers/IRObjDetector.cpp	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,132 @@
+#include "IRObjDetector.h"
+#include "tlc5916.h"
+
+#define DWELL_TIME 25       // Time to wait between enabling IR transmitter LED and reading ADC result, in us.
+
+void
+IRObjDetector::scan(void)
+{
+    int i;
+    uint32_t max = 0;
+    int32_t  tmp;
+    
+    //data[7] = ain.read_u16() >> 8; // Read the ambient level and store in last data slot.
+    data[7] = ain.read_u16(); // Read the ambient level and store in last data slot.    
+    
+    // Set the IR leds one at a time and read the reflection.    
+    for (i = 0; i < 7; i++)
+    {
+        // Write the value to enable the LED
+        tlc5916.write_reg(1 << i);
+        // Enable the selected LED.
+        tlc5916.enable();
+        // Wait for output to stabilize
+        wait_us(DWELL_TIME);
+        // Read ADC value and subtract off ambient.
+        //tmp = (ain.read_u16() >> 8) - data[7];
+        tmp = ain.read_u16() - data[7];
+        if (tmp < 0) 
+            data[i] = 0;
+        else
+            data[i] = tmp >> 8;
+        // Disable the selected LED.
+        tlc5916.disable();
+        
+        if (tmp > max) max = tmp;
+    }
+    
+    calc_centeroid();
+    
+    brightness = max;
+
+    brightnessBins[currentBin++] = brightness;
+
+    // Calculate running average over BRIGHTNESS_BINS bins.
+    minBrightness = 0xFFFF;
+    avgBrightness = 0;
+    maxBrightness = 0; 
+    for (int i = 0; i < BRIGHTNESS_BINS; i++)
+    {   
+        tmp = brightnessBins[i];
+        if (minBrightness > tmp) minBrightness = tmp;
+        avgBrightness += tmp;
+        if (maxBrightness < tmp) maxBrightness = tmp;
+    }
+    avgBrightness = avgBrightness / BRIGHTNESS_BINS;    
+
+    if (currentBin >= BRIGHTNESS_BINS)
+        currentBin = 0;
+}
+
+float
+IRObjDetector::get_weighted_avg_brightness(void)
+{   
+    if (debug != NULL)
+    {
+        debug->printf("IRObjDetector: Calculating weighted average.\r\n");
+        debug->printf("IRObjDetector: minBrightness = 0x%4.4x\r\n", minBrightness);
+        debug->printf("IRObjDetector: avgBrightness = 0x%4.4x\r\n", avgBrightness);
+        debug->printf("IRObjDetector: minBrightness = 0x%4.4x\r\n", maxBrightness);
+    }
+    return (float)(avgBrightness) / (float)0xffff;
+}
+
+void
+IRObjDetector::calc_centeroid(void)
+{
+    int i;
+    
+    uint32_t low;
+    float sumA, sumB;
+    
+    low = 0xffff;
+    for (i = 0; i < 7; i++)
+    {
+        if (data[i] < low) low = data[i];
+    }
+    
+    sumA = sumB = 0;
+    
+    // Generate sums for centeroid data
+    for (i = 0; i < 7; i++)
+    {
+        sumB += (data[i] - low) * (i + 1);
+        sumA += data[i] - low;
+    }
+    
+    // Get 'center' bin by taking the highest bin count and dividing by number of bins.
+    float offset = 28/7;
+    
+    centeroid = sumB / sumA;  // Generate centroid (approximate location of object) which is a number between 1 an nBins (7 in our case)
+    centeroid -= offset; // Offset the centeroid around center bin, now the centeroid is a number between 1-offset and offset-1 (-3 to 3 in our case)
+}
+
+float
+IRObjDetector::get_centeroid(void)
+{
+    return centeroid;
+}
+
+uint16_t
+IRObjDetector::get_raw_brightness(void)
+{
+    return brightness;
+}
+
+uint16_t
+IRObjDetector::get_min_brightness(void)
+{
+    return minBrightness;
+}
+
+uint16_t
+IRObjDetector::get_avg_brightness(void)
+{
+    return avgBrightness;
+}
+
+uint16_t
+IRObjDetector::get_max_brightness(void)
+{
+    return maxBrightness;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PiSlingers/IRObjDetector.h	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,79 @@
+#ifndef _IROBJDETECTOR_H_
+#define _IROBJDETECTOR_H_
+
+#include "mbed.h"
+#include "tlc5916.h"
+
+#define BRIGHTNESS_BINS 16
+
+class IRObjDetector
+{
+public:
+    IRObjDetector(void) : tlc5916(p6, p5, p7, p11), ain(p18)
+    {
+        debug           = NULL;
+        minBrightness   = 0;
+        avgBrightness   = 0;
+        maxBrightness   = 0;
+        for (currentBin = 0; currentBin < BRIGHTNESS_BINS; currentBin++)
+        {
+            brightnessBins[currentBin] = 0;
+        }        
+        currentBin = 0;    
+    };
+    
+    IRObjDetector(Serial *debug) : debug(debug), tlc5916(p6, p5, p7, p11), ain(p18)
+    {
+        debug           = NULL;
+        minBrightness   = 0;
+        avgBrightness   = 0;
+        maxBrightness   = 0;
+        for (currentBin = 0; currentBin < BRIGHTNESS_BINS; currentBin++)
+        {
+            brightnessBins[currentBin] = 0;
+        }        
+        currentBin = 0;    
+    };
+    
+    /**
+     * Scan through all 7 LED's and store the values.
+     */
+    void scan(void);
+    
+    /**
+     * Get the centeroid value of the scaned field.
+     */
+    float get_centeroid(void);
+    
+    /**
+     * Get the 'raw' brightness value.
+     */
+    uint16_t get_raw_brightness(void);
+    uint16_t get_min_brightness(void);
+    uint16_t get_avg_brightness(void);
+    uint16_t get_max_brightness(void);
+    float    get_weighted_avg_brightness(void);
+     
+private:
+
+    void calc_centeroid(void);
+    void calc_contrast(void);
+
+    Serial     *debug;    
+    TLC5916     tlc5916;
+    AnalogIn    ain;
+    uint16_t    data[8]; //Bin 7 is the 'all off' bin.
+    float       centeroid;
+    uint16_t    brightness;
+    uint16_t    brightnessBins[BRIGHTNESS_BINS]; // Used to calculate average brightness
+    uint8_t     currentBin;
+    uint32_t    avgBrightness;
+    uint16_t    maxBrightness;
+    uint16_t    minBrightness;
+
+    
+    float       mean;
+    float       map;
+};
+
+#endif //_IROBJDETECTOR_H_
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PiSlingers/tlc5916.cpp	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,26 @@
+
+#include "mbed.h"
+#include "tlc5916.h"
+
+void
+TLC5916::write_reg(uint8_t byte)
+{
+    pinLE = 0;
+    spi.write(byte);
+    wait_us(1);
+    pinLE = 1;
+    wait_us(1);
+    pinLE = 0;
+}
+
+void
+TLC5916::enable(void)
+{
+    pinnOE = 0;
+}
+
+void
+TLC5916::disable(void)
+{
+    pinnOE = 1;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PiSlingers/tlc5916.h	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,28 @@
+#ifndef _TLC5916_H_
+#define _TLC5916_H_
+
+class TLC5916 {
+
+public:
+    TLC5916(PinName le, PinName sin, PinName clk, PinName nOE) : pinLE(le), pinnOE(nOE), spi(sin, NC, clk)
+    {
+        pinLE   = 0;
+        pinnOE  = 1;
+        
+        spi.format(8,0);
+        spi.frequency(1000000);        
+    };
+    
+    void write_reg(uint8_t byte);
+    void enable(void);
+    void disable(void);
+    
+private:
+
+    DigitalOut  pinLE;
+    DigitalOut  pinnOE;
+    SPI         spi;
+
+};
+
+#endif //_TLC5916_H_
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m3pi/.lib	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/chris/libraries/m3pi/lr20a4
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m3pi/m3pi.cpp	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,238 @@
+/* m3pi Library
+ *
+ * Copyright (c) 2007-2010 cstyles
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "mbed.h"
+#include "m3pi.h"
+
+m3pi::m3pi(PinName nrst, PinName tx, PinName rx) :  Stream("m3pi"), _nrst(nrst), _ser(tx, rx)  {
+    _ser.baud(115200);
+    reset();
+}
+
+m3pi::m3pi() :  Stream("m3pi"), _nrst(p23), _ser(p9, p10)  {
+    _ser.baud(115200);
+    reset();
+}
+
+
+void m3pi::reset () {
+    _nrst = 0;
+    wait (0.01);
+    _nrst = 1;
+    wait (0.1);
+}
+
+void m3pi::left_motor (float speed) {
+    motor(0,speed);
+}
+
+void m3pi::right_motor (float speed) {
+    motor(1,speed);
+}
+
+void m3pi::forward (float speed) {
+    motor(0,speed);
+    motor(1,speed);
+}
+
+void m3pi::backward (float speed) {
+    motor(0,-1.0*speed);
+    motor(1,-1.0*speed);
+}
+
+void m3pi::left (float speed) {
+    motor(0,speed);
+    motor(1,-1.0*speed);
+}
+
+void m3pi::right (float speed) {
+    motor(0,-1.0*speed);
+    motor(1,speed);
+}
+
+void m3pi::stop (void) {
+    motor(0,0.0);
+    motor(1,0.0);
+}
+
+void m3pi::motor (int motor, float speed) {
+    char opcode = 0x0;
+    if (speed > 0.0) {
+        if (motor==1)
+            opcode = M1_FORWARD;
+        else
+            opcode = M2_FORWARD;
+    } else {
+        if (motor==1)
+            opcode = M1_BACKWARD;
+        else
+            opcode = M2_BACKWARD;
+    }
+    unsigned char arg = 0x7f * abs(speed);
+
+    _ser.putc(opcode);
+    _ser.putc(arg);
+}
+
+float m3pi::battery() {
+    _ser.putc(SEND_BATTERY_MILLIVOLTS);
+    char lowbyte = _ser.getc();
+    char hibyte  = _ser.getc();
+    float v = ((lowbyte + (hibyte << 8))/1000.0);
+    return(v);
+}
+
+float m3pi::line_position() {
+    int pos = 0;
+    _ser.putc(SEND_LINE_POSITION);
+    pos = _ser.getc();
+    pos += _ser.getc() << 8;
+    
+    float fpos = ((float)pos - 2048.0)/2048.0;
+    return(fpos);
+}
+
+const m3pi::LineSensors m3pi::get_raw_sensors(void) {
+    static LineSensors sensors;
+    
+    _ser.putc(SEND_RAW_SENSOR_VALUES);
+    
+    sensors.sensor1 = _ser.getc();
+    sensors.sensor1 |= _ser.getc() << 8;
+    sensors.sensor2 = _ser.getc();
+    sensors.sensor2 |= _ser.getc() << 8;
+    sensors.sensor3 = _ser.getc();
+    sensors.sensor3 |= _ser.getc() << 8;
+    sensors.sensor4 = _ser.getc();
+    sensors.sensor4 |= _ser.getc() << 8;
+    sensors.sensor5 = _ser.getc();
+    sensors.sensor5 |= _ser.getc() << 8;
+
+    return sensors;
+}
+
+char m3pi::sensor_auto_calibrate() {
+    _ser.putc(AUTO_CALIBRATE);
+    return(_ser.getc());
+}
+
+
+void m3pi::calibrate(void) {
+    _ser.putc(PI_CALIBRATE);
+}
+
+void m3pi::reset_calibration() {
+    _ser.putc(LINE_SENSORS_RESET_CALIBRATION);
+}
+
+void m3pi::PID_start(int max_speed, int a, int b, int c, int d) {
+    _ser.putc(max_speed);
+    _ser.putc(a);
+    _ser.putc(b);
+    _ser.putc(c);
+    _ser.putc(d);
+}
+
+void m3pi::PID_stop() {
+    _ser.putc(STOP_PID);
+}
+
+float m3pi::pot_voltage(void) {
+    int volt = 0;
+    _ser.putc(SEND_TRIMPOT);
+    volt = _ser.getc();
+    volt += _ser.getc() << 8;
+    return(volt);
+}
+
+
+void m3pi::leds(int val) {
+
+    BusOut _leds(p20,p19,p18,p17,p16,p15,p14,p13);
+    _leds = val;
+}
+
+
+void m3pi::locate(int x, int y) {
+    _ser.putc(DO_LCD_GOTO_XY);
+    _ser.putc(x);
+    _ser.putc(y);
+}
+
+void m3pi::cls(void) {
+    _ser.putc(DO_CLEAR);
+}
+
+int m3pi::print (char* text, int length) {
+    _ser.putc(DO_PRINT);  
+    _ser.putc(length);       
+    for (int i = 0 ; i < length ; i++) {
+        _ser.putc(text[i]); 
+    }
+    return(0);
+}
+
+int m3pi::_putc (int c) {
+    _ser.putc(DO_PRINT);  
+    _ser.putc(0x1);       
+    _ser.putc(c);         
+    wait (0.001);
+    return(c);
+}
+
+int m3pi::_getc (void) {
+    char r = 0;
+    return(r);
+}
+
+int m3pi::putc (int c) {
+    return(_ser.putc(c));
+}
+
+int m3pi::getc (void) {
+    return(_ser.getc());
+}
+
+
+
+
+
+#ifdef MBED_RPC
+const rpc_method *m3pi::get_rpc_methods() {
+    static const rpc_method rpc_methods[] = {{ "forward", rpc_method_caller<m3pi, float, &m3pi::forward> },
+        { "backward", rpc_method_caller<m3pi, float, &m3pi::backward> },
+        { "left", rpc_method_caller<m3pi, float, &m3pi::left> },
+        { "right", rpc_method_caller<m3pi, float, &m3pi::right> },
+        { "stop", rpc_method_caller<m3pi, &m3pi::stop> },
+        { "left_motor", rpc_method_caller<m3pi, float, &m3pi::left_motor> },
+        { "right_motor", rpc_method_caller<m3pi, float, &m3pi::right_motor> },
+        { "battery", rpc_method_caller<float, m3pi, &m3pi::battery> },
+        { "line_position", rpc_method_caller<float, m3pi, &m3pi::line_position> },
+        { "sensor_auto_calibrate", rpc_method_caller<char, m3pi, &m3pi::sensor_auto_calibrate> },
+
+
+        RPC_METHOD_SUPER(Base)
+    };
+    return rpc_methods;
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m3pi/m3pi.h	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,247 @@
+/* mbed m3pi Library
+ * Copyright (c) 2007-2010 cstyles
+ *
+ * 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 M3PI_H
+#define M3PI_H
+
+#include "mbed.h"
+#include "platform.h"
+
+#ifdef MBED_RPC
+#include "rpc.h"
+#endif
+
+#define SEND_SIGNATURE 0x81
+#define SEND_RAW_SENSOR_VALUES 0x86
+#define SEND_TRIMPOT 0xB0
+#define SEND_BATTERY_MILLIVOLTS 0xB1
+#define DO_PLAY 0xB3
+#define PI_CALIBRATE 0xB4
+#define DO_CLEAR 0xB7
+#define DO_PRINT 0xB8
+#define DO_LCD_GOTO_XY 0xB9
+#define LINE_SENSORS_RESET_CALIBRATION 0xB5
+#define SEND_LINE_POSITION 0xB6
+#define AUTO_CALIBRATE 0xBA
+#define SET_PID 0xBB
+#define STOP_PID 0xBC
+#define M1_FORWARD 0xC1
+#define M1_BACKWARD 0xC2
+#define M2_FORWARD 0xC5
+#define M2_BACKWARD 0xC6
+
+
+
+/** m3pi control class
+ *
+ * Example:
+ * @code
+ * // Drive the m3pi forward, turn left, back, turn right, at half speed for half a second
+
+   #include "mbed.h"
+   #include "m3pi.h"
+
+   m3pi pi;
+
+   int main() {
+
+     wait(0.5);
+
+     pi.forward(0.5);
+     wait (0.5);
+     pi.left(0.5);
+     wait (0.5);
+     pi.backward(0.5);
+     wait (0.5);
+     pi.right(0.5);
+     wait (0.5);
+
+     pi.stop();
+
+ }
+ * @endcode
+ */
+class m3pi :  public Stream {
+
+    // Public functions
+public:
+
+    /** Create the m3pi object connected to the default pins
+     *
+     * @param nrst GPIO pin used for reset. Default is p23
+     * @param tx Serial transmit pin. Default is p9
+     * @param rx Serial receive pin. Default is p10
+     */
+    m3pi();
+
+
+    /** Create the m3pi object connected to specific pins
+     *
+     */
+    m3pi(PinName nrst, PinName tx, PinName rx);
+
+
+
+    /** Force a hardware reset of the 3pi
+     */
+    void reset (void);
+
+    /** Directly control the speed and direction of the left motor
+     *
+     * @param speed A normalised number -1.0 - 1.0 represents the full range.
+     */
+    void left_motor (float speed);
+
+    /** Directly control the speed and direction of the right motor
+     *
+     * @param speed A normalised number -1.0 - 1.0 represents the full range.
+     */
+    void right_motor (float speed);
+
+    /** Drive both motors forward as the same speed
+     *
+     * @param speed A normalised number 0 - 1.0 represents the full range.
+     */
+    void forward (float speed);
+
+    /** Drive both motors backward as the same speed
+     *
+     * @param speed A normalised number 0 - 1.0 represents the full range.
+     */
+    void backward (float speed);
+
+    /** Drive left motor backwards and right motor forwards at the same speed to turn on the spot
+     *
+     * @param speed A normalised number 0 - 1.0 represents the full range.
+     */
+    void left (float speed);
+
+    /** Drive left motor forward and right motor backwards at the same speed to turn on the spot
+     * @param speed A normalised number 0 - 1.0 represents the full range.
+     */
+    void right (float speed);
+
+    /** Stop both motors
+     *
+     */
+    void stop (void);
+
+    /** Read the voltage of the potentiometer on the 3pi
+     * @returns voltage as a float
+     *
+     */
+    float pot_voltage(void);
+
+    /** Read the battery voltage on the 3pi
+     * @returns battery voltage as a float
+     */
+    float battery(void);
+
+    /** Read the position of the detected line
+     * @returns position as A normalised number -1.0 - 1.0 represents the full range.
+     *  -1.0 means line is on the left, or the line has been lost
+     *   0.0 means the line is in the middle
+     *   1.0 means the line is on the right
+     */
+    float line_position (void);
+
+
+    /** Calibrate the sensors. This turns the robot left then right, looking for a line
+     *
+     */
+    char sensor_auto_calibrate (void);
+
+    /** Set calibration manually to the current settings.
+     *
+     */
+    void calibrate(void);
+
+    /** Clear the current calibration settings
+     *
+     */
+    void reset_calibration (void);
+
+    void PID_start(int max_speed, int a, int b, int c, int d);
+
+    void PID_stop();
+
+    /** Write to the 8 LEDs
+     *
+     * @param leds An 8 bit value to put on the LEDs
+     */
+    void leds(int val);
+
+    /** Locate the cursor on the 8x2 LCD
+     *
+     * @param x The horizontal position, from 0 to 7
+     * @param y The vertical position, from 0 to 1
+     */
+    void locate(int x, int y);
+
+    /** Clear the LCD
+     *
+     */
+    void cls(void);
+
+    /** Send a character directly to the 3pi serial interface
+     * @param c The character to send to the 3pi
+     */
+    int putc(int c);
+
+    /** Receive a character directly to the 3pi serial interface
+     * @returns c The character received from the 3pi
+     */
+    int getc();
+
+    /** Send a string buffer to the 3pi serial interface
+     * @param text A pointer to a char array
+     * @param int The character to send to the 3pi
+     */
+    int print(char* text, int length);
+    
+    struct LineSensors {
+        uint16_t sensor1;
+        uint16_t sensor2;
+        uint16_t sensor3;
+        uint16_t sensor4;
+        uint16_t sensor5;
+    };
+    
+    const LineSensors get_raw_sensors(void);
+    
+
+#ifdef MBED_RPC
+    virtual const struct rpc_method *get_rpc_methods();
+#endif
+
+private :
+
+    DigitalOut _nrst;
+    Serial _ser;
+    
+    void motor (int motor, float speed);
+    virtual int _putc(int c);
+    virtual int _getc();
+
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,107 @@
+#include "mbed.h"
+#include "m3pi.h"
+#include "MODSERIAL.h"
+
+#include "tlc5916.h"
+#include "IRObjDetector.h"
+#include "IRBehaviorController.h"
+#include "Beacon.h"
+#include "PID.h"
+
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+
+//Serial          blueTooth(p13, p14);
+MODSERIAL       blueTooth(p13, p14);
+Ticker          taskTimer;
+m3pi            base;
+
+// PID terms
+#define P_TERM    0.04f
+#define I_TERM    0.00f
+#define D_TERM    0.00f
+#define THRESHOLD 0.30f
+//PID                  pid(P_TERM, I_TERM, D_TERM, &blueTooth);
+PID                  pid(P_TERM, I_TERM, D_TERM);
+//IRObjDetector        ird(&blueTooth);
+//IRBehaviorController irController(&pid, &blueTooth);
+IRBehaviorController irController(&pid);
+Beacon               beacon;
+
+
+void 
+taskFunc(void)
+{
+//    blueTooth.printf("\e[1J");      // Clear terminal screen
+//    blueTooth.printf("\e[H");       // Home terminal screen
+//    blueTooth.printf("Task exec.\r\n");
+    //irController.runSeeking();
+    irController.runAvoidance();
+    led1 = !led1;
+}
+
+int 
+main() 
+{
+    float power = 0.00f;
+    float speed = 0.20f;
+    float max   = 1.00f;
+    float right, left;
+   
+    //FunctionPointer ird_scan(&ird, &IRObjDetector::scan);
+    
+        
+    base.reset();
+    base.locate(0, 0);
+    base.printf("IR Track");
+    wait(10);
+    
+    blueTooth.baud(115200);
+    blueTooth.printf("\r\nSystem start!\r\n");
+ 
+    irController.setActiveThreshold(THRESHOLD);
+    
+    //taskTimer.attach(&irController, &IRBehaviorController::runSeeking, 0.1);
+    taskTimer.attach(&taskFunc, 0.01);
+        
+    while(1)
+    {
+        blueTooth.printf("\e[1J");      // Clear terminal screen
+        blueTooth.printf("\e[H");       // Home terminal screen
+        blueTooth.printf("Main Loop Start.\r\n");
+        blueTooth.printf("MAIN: Battery Voltage:\t%1.2f\r\n", base.battery());    
+        
+        pid.dumpDebug(&blueTooth);
+        irController.dumpDebug(&blueTooth);
+        
+        power = irController.getPower();
+        
+        
+        right = speed - power;
+        left  = speed + power;
+        
+        if (right < -max)
+            right = -max;
+        if (right > max)
+            right = max;
+            
+        if (left < -max)
+            left = -max;
+        if (left > max)
+            left = max;
+        
+        blueTooth.printf("MAIN: power = %3.2f\r\n", power);
+        blueTooth.printf("MAIN: speed = %3.2f\r\n", speed);
+        blueTooth.printf("MAIN: left  = %3.2f\r\n", left);
+        blueTooth.printf("MAIN: right = %3.2f\r\n", right);
+        
+        base.left_motor(left);
+        base.right_motor(right);
+        
+        blueTooth.printf("Main Loop End.\r\n");
+        wait(0.1);
+    };
+    
+//    testIRObjDet();
+            
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.lib	Wed Apr 04 17:07:49 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/projects/libraries/svn/mbed/trunk@43
\ No newline at end of file