This program shows how to use the MODSERIAL library by Andy Kirkham to do canonical input processing. This allows you to enter and edit a command line (in the same way that you do in DOS or Linux) without tying up your main routine.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MODSERIAL.h Source File

MODSERIAL.h

00001 /*
00002     Copyright (c) 2010 Andy Kirkham
00003  
00004     Permission is hereby granted, free of charge, to any person obtaining a copy
00005     of this software and associated documentation files (the "Software"), to deal
00006     in the Software without restriction, including without limitation the rights
00007     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008     copies of the Software, and to permit persons to whom the Software is
00009     furnished to do so, subject to the following conditions:
00010  
00011     The above copyright notice and this permission notice shall be included in
00012     all copies or substantial portions of the Software.
00013  
00014     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00019     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00020     THE SOFTWARE.
00021     
00022     @file          MODSERIAL.h 
00023     @purpose       Extends Serial to provide fully buffered IO
00024     @version       see ChangeLog.c
00025     @date          Nov 2010
00026     @author        Andy Kirkham
00027 */
00028 
00029 #ifndef MODSERIAL_H
00030 #define MODSERIAL_H
00031 
00032 /** @defgroup API The MODSERIAL API */
00033 /** @defgroup MISC Misc MODSERIAL functions */
00034 /** @defgroup INTERNALS MODSERIAL Internals */
00035 
00036 #ifndef MODSERIAL_DEFAULT_RX_BUFFER_SIZE
00037 #define MODSERIAL_DEFAULT_RX_BUFFER_SIZE    256
00038 #endif
00039 
00040 #ifndef MODSERIAL_DEFAULT_TX_BUFFER_SIZE
00041 #define MODSERIAL_DEFAULT_TX_BUFFER_SIZE    256
00042 #endif
00043 
00044 #include "mbed.h"
00045 
00046 namespace AjK {
00047 
00048 // Forward reference.
00049 class MODSERIAL ;
00050 
00051 /**
00052  * @author Andy Kirkham
00053  * @see http://mbed.org/cookbook/MODSERIAL
00054  * @see example3a.cpp
00055  * @see example3b.cpp
00056  * @see API 
00057  *
00058  * <b>MODSERIAL_IRQ_INFO</b> is a class used to pass information (and access to protected
00059  * MODSERIAL functions) to IRQ callbacks. 
00060  */
00061 class MODSERIAL_IRQ_INFO 
00062 {
00063 public:
00064     friend class MODSERIAL ;
00065     
00066     MODSERIAL  *serial;
00067     
00068     MODSERIAL_IRQ_INFO () { serial = 0; }
00069     
00070     /** rxDiscardLastChar()
00071      *
00072      * Remove the last char placed into the rx buffer.
00073      * This is an operation that can only be performed
00074      * by an rxCallback function. 
00075      * @ingroup API
00076      * @return The byte removed from the buffer.
00077      */
00078     int rxDiscardLastChar(void);
00079 
00080 protected:
00081 
00082     /** setSerial()
00083      *
00084      * Used internally by MODSERIAL to set the "this" pointer
00085      * of the MODSERIAL that created this object.
00086      * @ingroup INTERNAL
00087      * @param A pointer to a MODSERIAL object instance.
00088      */
00089     void setSerial(MODSERIAL  *s) { serial = s; }    
00090 };
00091 
00092 // Forward reference dummy class.
00093 class MODSERIAL_callback_dummy;
00094 
00095 /**
00096  * @author Andy Kirkham
00097  * @see http://mbed.org/cookbook/MODSERIAL
00098  * @see example3a.cpp
00099  * @see example3b.cpp
00100  * @see API 
00101  *
00102  * <b>MODSERIAL_callback</b> is a class used to hold application callbacks that
00103  * MODSERIAL can invoke on certain events.
00104  */
00105 class MODSERIAL_callback  
00106 {
00107 protected:
00108 
00109     //! C callback function pointer.
00110     void (*c_callback)(MODSERIAL_IRQ_INFO  *); 
00111     
00112     //! C++ callback object/method pointer (the object part).
00113     MODSERIAL_callback_dummy *obj_callback;
00114     
00115     //! C++ callback object/method pointer (the method part).
00116     void (MODSERIAL_callback_dummy::*method_callback)(MODSERIAL_IRQ_INFO  *);
00117 
00118 public:
00119     
00120     /** Constructor
00121      */
00122     MODSERIAL_callback() {
00123         c_callback      = 0;
00124         obj_callback    = 0;
00125         method_callback = 0;
00126     }
00127     
00128     /** attach - Overloaded attachment function.
00129      *
00130      * Attach a C type function pointer as the callback.
00131      *
00132      * Note, the callback function prototype must be:-
00133      * @code
00134      * void myCallbackFunction(MODSERIAL_IRQ_INFO *);
00135      * @endcode
00136      * @param A C function pointer to call.
00137      */
00138     void attach(void (*function)(MODSERIAL_IRQ_INFO  *) = 0) { c_callback = function; }
00139     
00140     /** attach - Overloaded attachment function.
00141      *
00142      * Attach a C++ type object/method pointer as the callback.
00143      *
00144      * Note, the callback method prototype must be:-
00145      * @code
00146      *     public:
00147      *         void myCallbackFunction(MODSERIAL_IRQ_INFO *);
00148      * @endcode
00149      * @param A C++ object pointer.
00150      * @param A C++ method within the object to call.
00151      */
00152     template<class T> 
00153     void attach(T* item, void (T::*method)(MODSERIAL_IRQ_INFO  *)) { 
00154         obj_callback    = (MODSERIAL_callback_dummy *)item; 
00155         method_callback = (void (MODSERIAL_callback_dummy::*)(MODSERIAL_IRQ_INFO  *))method; 
00156     }
00157 
00158     /** call - Overloaded callback initiator.
00159      *
00160      * call the callback function.
00161      *
00162      * @param uint32_t The value to pass to the callback.
00163      * @return uint32_t The value the callback returns.
00164      */
00165     void call(MODSERIAL_IRQ_INFO  *arg) {
00166         if (c_callback != 0) {
00167             (*c_callback)(arg);
00168         }
00169         else {
00170             if (obj_callback  != 0 && method_callback != 0) {
00171                 (obj_callback->*method_callback)(arg);
00172             }
00173         }       
00174     }    
00175 };
00176 
00177 /**
00178  * @author Andy Kirkham
00179  * @see http://mbed.org/cookbook/MODSERIAL
00180  * @see http://mbed.org/handbook/Serial
00181  * @see example1.cpp
00182  * @see example2.cpp
00183  * @see example3a.cpp
00184  * @see example3b.cpp
00185  * @see example_dma.cpp
00186  * @see API 
00187  *
00188  * <b>MODSERIAL</b> extends the Mbed library <a href="/handbook/Serial">Serial</a> to provide fully buffered
00189  * TX and RX streams. Buffer length is fully customisable. 
00190  *
00191  * Before using MODSERIAL users should be familar with Mbed's standard <a href="/handbook/Serial">Serial</a>
00192  * library object. MODSERIAL is a direct "drop in" replacement for <a href="/handbook/Serial">Serial</a>. Where
00193  * previously Serial was used, MODSERIAL can be used as adirect replacement instantly offering standard
00194  * TX and RX buffering. By default, both TX and RX buffers are 256 bytes in length.
00195  *
00196  * @image html /media/uploads/mbedofficial/serial_interfaces.png
00197  *
00198  * Standard example:
00199  * @code
00200  * #include "mbed.h"
00201  * #include "MODSERIAL.h"
00202  *
00203  * MODSERIAL pc(USBTX, USBRX); // tx, rx
00204  *
00205  * int main() {
00206  *     pc.printf("Hello World!");
00207  *     while(1) {
00208  *         pc.putc(pc.getc() + 1);
00209  *     }
00210  * }
00211  * @endcode
00212  *
00213  * Example with alternate buffer length:
00214  * @code
00215  * #include "mbed.h"
00216  * #include "MODSERIAL.h"
00217  *
00218  * // Make TX and RX buffers 512byes in length
00219  * MODSERIAL pc(USBTX, USBRX, 512); // tx, rx
00220  *
00221  * int main() {
00222  *     pc.printf("Hello World!");
00223  *     while(1) {
00224  *         pc.putc(pc.getc() + 1);
00225  *     }
00226  * }
00227  * @endcode
00228  *
00229  * Example with alternate buffer length:
00230  * @code
00231  * #include "mbed.h"
00232  * #include "MODSERIAL.h"
00233  *
00234  * // Make TX 1024bytes and RX 512byes in length
00235  * MODSERIAL pc(USBTX, USBRX, 1024, 512); // tx, rx
00236  *
00237  * int main() {
00238  *     pc.printf("Hello World!");
00239  *     while(1) {
00240  *         pc.putc(pc.getc() + 1);
00241  *     }
00242  * }
00243  * @endcode
00244  */
00245 class MODSERIAL  : public Serial 
00246 {
00247 public:
00248 
00249     // Allow instances of MODSERIAL_IRQ_INFO to use protected properties and methods.
00250     friend class MODSERIAL_IRQ_INFO ;
00251 
00252     //! A copy of the Serial parity enum
00253     /** @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.format */
00254     enum Parity {
00255           None = 0
00256         , Odd
00257         , Even
00258         , Forced1   
00259         , Forced0
00260     };
00261     
00262     //! A copy of the Serial IrqType enum
00263     enum IrqType {
00264           RxIrq = 0
00265         , TxIrq
00266         , RxOvIrq
00267         , TxOvIrq
00268         , TxEmpty
00269         , RxAutoDetect
00270         , NumOfIrqTypes
00271     };
00272     
00273     //! Non-blocking functions return code.
00274     enum Result {
00275           Ok  = 0                /*!< Ok. */
00276         , NoMemory        = -1   /*!< Memory allocation failed. */
00277         , NoChar          = -1   /*!< No character in buffer. */
00278         , BufferOversize  = -2   /*!< Oversized buffer. */
00279     };
00280     
00281     /**
00282      * The MODSERIAL constructor is used to initialise the serial object.
00283      *
00284      * @param tx PinName of the TX pin.
00285      * @param rx PinName of the TX pin.
00286      * @param name An option name for RPC usage.
00287      */    
00288     MODSERIAL(PinName tx, PinName rx, const char *name = NULL);
00289     
00290     /**
00291      * The MODSERIAL constructor is used to initialise the serial object.
00292      *
00293      * @param tx PinName of the TX pin.
00294      * @param rx PinName of the TX pin.
00295      * @param bufferSize Integer of the TX and RX buffer sizes.
00296      * @param name An option name for RPC usage.
00297      */    
00298     MODSERIAL(PinName tx, PinName rx, int bufferSize, const char *name = NULL);
00299     
00300     /**
00301      * The MODSERIAL constructor is used to initialise the serial object.
00302      *
00303      * @param tx PinName of the TX pin.
00304      * @param rx PinName of the TX pin.
00305      * @param txBufferSize Integer of the TX buffer sizes.
00306      * @param rxBufferSize Integer of the RX buffer sizes.
00307      * @param name An option name for RPC usage.
00308      */    
00309     MODSERIAL(PinName tx, PinName rx, int txBufferSize, int rxBufferSize, const char *name = NULL);
00310     
00311     virtual ~MODSERIAL ();
00312 
00313     /**
00314      * Function: attach
00315      *  
00316      * The Mbed standard <a href="/handbook/Serial">Serial</a> library object allows an interrupt callback
00317      * to be made when a byte is received by the TX or RX UART hardware. MODSERIAL traps these interrupts
00318      * to enable it's buffering system. However, after the byte has been received/sent under interrupt control, 
00319      * MODSERIAL can callback a user function as a notification of the interrupt. Note, user code should not
00320      * directly interact with the Uart hardware, MODSERIAL does that, instead, MODSERIAL API functions should
00321      * be used.
00322      *
00323      * <b>Note</b>, a character is written out then, if there is room in the TX FIFO and the TX buffer is empty,
00324      * putc() will put the character directly into THR (the output holding register). If the TX FIFO is full and 
00325      * cannot accept the character, it is placed into the TX output buffer. The TX interrupts are then enabled
00326      * so that when the TX FIFO empties, the TX buffer is then transferred to the THR FIFO. The TxIrq will ONLY 
00327      * be activated when this transfer of a character from BUFFER to THR FIFO takes place. If your character 
00328      * throughput is not high bandwidth, then the 16 byte TX FIFO may be enough and the TX output buffer may 
00329      * never come into play.
00330      *
00331      * @code
00332      * #include "mbed.h"
00333      * #include "MODSERIAL.h"
00334      *
00335      * DigitalOut led1(LED1);
00336      * DigitalOut led2(LED2);
00337      * DigitalOut led3(LED3);
00338      *
00339      * // To test, connect p9 to p10 as a loopback.
00340      * MODSERIAL pc(p9, p10);
00341      *
00342      * // This function is called when a character goes into the TX buffer.
00343      * void txCallback(void) {
00344      *     led2 = !led2;
00345      * }
00346      *
00347      * // This function is called when a character goes into the RX buffer.
00348      * void rxCallback(void) {
00349      *     led3 = !led3;
00350      * }
00351      *
00352      * int main() {
00353      *     pc.baud(115200);
00354      *     pc.attach(&txCallback, MODSERIAL::TxIrq);
00355      *     pc.attach(&rxCallback, MODSERIAL::RxIrq);
00356      *
00357      *     while(1) {
00358      *         led1 = !led1;
00359      *         wait(0.5);
00360      *         pc.putc('A');
00361      *         wait(0.5);
00362      *     }
00363      * ]
00364      * @endcode
00365      *
00366      * @ingroup API
00367      * @param fptr A pointer to a void function, or 0 to set as none
00368      * @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
00369      */  
00370     void attach(void (*fptr)(MODSERIAL_IRQ_INFO  *), IrqType type = RxIrq) { _isr[type].attach(fptr); }
00371     
00372     /**
00373      * Function: attach
00374      *  
00375      * The Mbed standard <a href="/handbook/Serial">Serial</a> library object allows an interrupt callback
00376      * to be made when a byte is received by the TX or RX UART hardware. MODSERIAL traps these interrupts
00377      * to enable it's buffering system. However, after the byte has been received/sent under interrupt control, 
00378      * MODSERIAL can callback a user function as a notification of the interrupt. Note, user code should not
00379      * directly interact with the Uart hardware, MODSERIAL does that, instead, MODSERIAL API functions should
00380      * be used.
00381      *
00382      * <b>Note</b>, a character is written out then, if there is room in the TX FIFO and the TX buffer is empty,
00383      * putc() will put the character directly into THR (the output holding register). If the TX FIFO is full and 
00384      * cannot accept the character, it is placed into the TX output buffer. The TX interrupts are then enabled
00385      * so that when the TX FIFO empties, the TX buffer is then transferred to the THR FIFO. The TxIrq will ONLY 
00386      * be activated when this transfer of a character from BUFFER to THR FIFO takes place. If your character 
00387      * throughput is not high bandwidth, then the 16 byte TX FIFO may be enough and the TX output buffer may 
00388      * never come into play.
00389      *
00390      * @code
00391      * #include "mbed.h"
00392      * #include "MODSERIAL.h"
00393      *
00394      * DigitalOut led1(LED1);
00395      * DigitalOut led2(LED2);
00396      * DigitalOut led3(LED3);
00397      *
00398      * // To test, connect p9 to p10 as a loopback.
00399      * MODSERIAL pc(p9, p10);
00400      *
00401      * class Foo {
00402      * public:
00403      *     // This method is called when a character goes into the TX buffer.
00404      *     void txCallback(void) { led2 = !led2; }
00405      *
00406      *     // This method is called when a character goes into the RX buffer.
00407      *     void rxCallback(void) { led3 = !led3; }
00408      * };
00409      *
00410      * Foo foo;
00411      *
00412      * int main() {
00413      *     pc.baud(115200);
00414      *     pc.attach(&foo, &Foo::txCallback, MODSERIAL::TxIrq);
00415      *     pc.attach(&foo, &Foo::rxCallback, MODSERIAL::RxIrq);
00416      *
00417      *     while(1) {
00418      *         led1 = !led1;
00419      *         wait(0.5);
00420      *         pc.putc('A');
00421      *         wait(0.5);
00422      *     }
00423      * ]
00424      * @endcode
00425      *     
00426      * @ingroup API
00427      * @param  tptr A pointer to the object to call the member function on
00428      * @param  mptr A pointer to the member function to be called
00429      * @param  type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
00430      */
00431     template<typename T>
00432     void attach(T* tptr, uint32_t (T::*mptr)(uint32_t), IrqType type = RxIrq) {
00433         if((mptr != 0) && (tptr != 0)) {
00434             _isr[type].attach(tptr, mptr);            
00435         }
00436     }
00437 
00438     /**
00439      * @see attach
00440      * @ingroup API
00441      */
00442     void connect (void (*fptr)(MODSERIAL_IRQ_INFO  *), IrqType type = RxIrq) { _isr[RxIrq].attach(fptr); }
00443     
00444     /**
00445      * @see attach
00446      * @ingroup API
00447      */
00448     template<typename T>
00449     void connect (T* tptr, void (T::*mptr)(MODSERIAL_IRQ_INFO  *), IrqType type = RxIrq) {
00450         if((mptr != 0) && (tptr != 0)) {
00451             _isr[type].attach(tptr, mptr);            
00452         }
00453     }
00454     
00455     /**
00456      * Function: writeable
00457      *  
00458      * Determine if there is space available to write a byte
00459      *
00460      * @ingroup API
00461      * @return 1 if there is space to write a character, else 0
00462      */
00463     int writeable() { return txBufferFull() ? 0 : 1; }
00464     
00465     /**
00466      * Function: readable
00467      *  
00468      * Determine if there is a byte available to read
00469      *
00470      * @ingroup API
00471      * @return 1 if there is a character available to read, else 0
00472      */
00473     int readable() { return rxBufferEmpty() ? 0 : 1; } 
00474     
00475     /**
00476      * Function: txBufferSane
00477      *  
00478      * Determine if the TX buffer has been initialized.
00479      *
00480      * @ingroup API
00481      * @return true if the buffer is initialized, else false
00482      */
00483     bool txBufferSane(void) { return buffer[TxIrq] != (char *)NULL ? true : false; }
00484     
00485     /**
00486      * Function: rxBufferSane
00487      *  
00488      * Determine if the RX buffer has been initialized.
00489      *
00490      * @ingroup API
00491      * @return true if the buffer is initialized, else false
00492      */
00493     bool rxBufferSane(void) { return buffer[TxIrq] != (char *)NULL ? true : false; }
00494     
00495     /**
00496      * Function: txBufferGetCount
00497      *  
00498      * Returns how many bytes are in the TX buffer
00499      *
00500      * @ingroup API
00501      * @return The number of bytes in the TX buffer
00502      */
00503     int txBufferGetCount(void)    { return buffer_count[TxIrq]; }
00504     
00505     /**
00506      * Function: rxBufferGetCount
00507      *  
00508      * Returns how many bytes are in the RX buffer
00509      *
00510      * @ingroup API
00511      * @return The number of bytes in the RX buffer
00512      */
00513     int rxBufferGetCount(void)    { return buffer_count[RxIrq]; }
00514     
00515     /**
00516      * Function: txBufferGetSize
00517      *  
00518      * Returns the current size of the TX buffer
00519      *
00520      * @ingroup API
00521      * @return The length iof the TX buffer in bytes
00522      */
00523     int txBufferGetSize(int size) { return buffer_size[TxIrq]; } 
00524     
00525     /**
00526      * Function: rxBufferGetSize
00527      *  
00528      * Returns the current size of the RX buffer
00529      *
00530      * @ingroup API
00531      * @return The length iof the RX buffer in bytes
00532      */
00533     int rxBufferGetSize(int size) { return buffer_size[RxIrq]; } 
00534     
00535     /**
00536      * Function: txBufferFull
00537      *  
00538      * Is the TX buffer full?
00539      *
00540      * @ingroup API
00541      * @return true if the TX buffer is full, otherwise false
00542      */
00543     bool txBufferFull(void);
00544     
00545     /**
00546      * Function: rxBufferFull
00547      *  
00548      * Is the RX buffer full?
00549      *
00550      * @ingroup API
00551      * @return true if the RX buffer is full, otherwise false
00552      */
00553     bool rxBufferFull(void);
00554     
00555     /**
00556      * Function: txBufferEmpty
00557      *  
00558      * Is the TX buffer empty?
00559      *
00560      * @ingroup API
00561      * @return true if the TX buffer is empty, otherwise false
00562      */
00563     bool txBufferEmpty(void);
00564     
00565     /**
00566      * Function: rxBufferEmpty
00567      *  
00568      * Is the RX buffer empty?
00569      *
00570      * @ingroup API
00571      * @return true if the RX buffer is empty, otherwise false
00572      */
00573     bool rxBufferEmpty(void);
00574     
00575     /**
00576      * Function: txBufferSetSize
00577      *  
00578      * Change the TX buffer size.
00579      *
00580      * @see Result
00581      * @ingroup API
00582      * @param size The new TX buffer size in bytes.
00583      * @param m Perform a memory sanity check. Errs the Mbed if memory alloc fails.
00584      * @return Result Ok on success.
00585      */
00586     int txBufferSetSize(int size, bool m) { return resizeBuffer(size, TxIrq, m); } 
00587     
00588     /**
00589      * Function: rxBufferSetSize
00590      *  
00591      * Change the RX buffer size.
00592      *
00593      * @see Result
00594      * @ingroup API
00595      * @param size The new RX buffer size in bytes.
00596      * @param m Perform a memory sanity check. Errs the Mbed if memory alloc fails.
00597      * @return Result Ok on success.
00598      */
00599     int rxBufferSetSize(int size, bool m) { return resizeBuffer(size, RxIrq, m); } 
00600     
00601     /**
00602      * Function: txBufferSetSize
00603      *  
00604      * Change the TX buffer size.
00605      * Always performs a memory sanity check, halting the Mbed on failure.
00606      *
00607      * @see Result
00608      * @ingroup API
00609      * @param size The new TX buffer size in bytes.
00610      * @return Result Ok on success.
00611      */
00612     int txBufferSetSize(int size) { return resizeBuffer(size, TxIrq, true); } 
00613     
00614     /**
00615      * Function: rxBufferSetSize
00616      *  
00617      * Change the RX buffer size.
00618      * Always performs a memory sanity check, halting the Mbed on failure.
00619      *
00620      * @see Result
00621      * @ingroup API
00622      * @param size The new RX buffer size in bytes.
00623      * @return Result Ok on success.
00624      */
00625     int rxBufferSetSize(int size) { return resizeBuffer(size, RxIrq, true); } 
00626     
00627     /**
00628      * Function: txBufferFlush
00629      *  
00630      * Remove all bytes from the TX buffer.
00631      * @ingroup API
00632      */
00633     void txBufferFlush(void) { flushBuffer(TxIrq); }
00634     
00635     /**
00636      * Function: rxBufferFlush
00637      *  
00638      * Remove all bytes from the RX buffer.
00639      * @ingroup API
00640      */
00641     void rxBufferFlush(void) { flushBuffer(RxIrq); }
00642         
00643     /**
00644      * Function: getcNb
00645      *
00646      * Like getc() but is non-blocking. If no bytes are in the RX buffer this
00647      * function returns Result::NoChar (-1)
00648      *
00649      * @ingroup API
00650      * @return A byte from the RX buffer or Result::NoChar (-1) if bufer empty.
00651      */
00652     int getcNb() { return __getc(false); }
00653     
00654     /**
00655      * Function: getc
00656      *
00657      * Overloaded version of Serial::getc()
00658      * 
00659      * This function blocks (if the RX buffer is empty the function will wait for a
00660      * character to arrive and then return that character).
00661      *
00662      * @ingroup API
00663      * @return A byte from the RX buffer
00664      */
00665     int getc()   { return __getc(true);  }
00666     
00667     /**
00668      * Function: txGetLastChar
00669      *
00670      * Rteurn the last byte to pass through the TX interrupt handler.
00671      *
00672      * @ingroup MISC
00673      * @return The byte
00674      */
00675     char txGetLastChar(void) { return txc; }
00676     
00677     /**
00678      * Function: rxGetLastChar
00679      *
00680      * Return the last byte to pass through the RX interrupt handler.
00681      *
00682      * @ingroup MISC
00683      * @return The byte
00684      */
00685     char rxGetLastChar(void) { return rxc; }
00686     
00687     /**
00688      * Function: txIsBusy
00689      *
00690      * If the Uart is still actively sending characters this
00691      * function will return true.
00692      *
00693      * @ingroup API
00694      * @return bool
00695      */
00696     bool txIsBusy(void);
00697     
00698     /**
00699      * Function: autoDetectChar
00700      *
00701      * Set the char that, if seen incoming, invokes the AutoDetectChar callback.
00702      *
00703      * @ingroup API
00704      * @param int c The character to detect.
00705      */
00706     void autoDetectChar(char c) { auto_detect_char = c; }
00707     
00708     /**
00709      * Function: move
00710      *
00711      * Move contents of RX buffer to external buffer. Stops if "end" detected.
00712      *
00713      * @ingroup API
00714      * @param char *s The destination buffer address
00715      * @param int max The maximum number of chars to move.
00716      * @param char end If this char is detected stop moving.
00717      */
00718     int move(char *s, int max, char end) {
00719         int counter = 0;
00720         char c;
00721         while(readable()) {
00722             c = getc();
00723             if (c == end) break;
00724             *(s++) = c;
00725             counter++;
00726             if (counter == max) break;
00727         }
00728         return counter;
00729     }
00730     
00731     /**
00732      * Function: move (overloaded)
00733      *
00734      * Move contents of RX buffer to external buffer. Stops if auto_detect_char detected.
00735      *
00736      * @ingroup API
00737      * @param int max The maximum number of chars to move.
00738      * @param char *s The destination buffer address
00739      */
00740     int move(char *s, int max) {
00741         return move(s, max, auto_detect_char);
00742     }
00743     
00744     #if 0 // Inhereted from Serial/Stream, for documentation only
00745     /**
00746      * Function: putc
00747      * 
00748      * Write a character
00749      * Inhereted from Serial/Stream
00750      *
00751      * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.putc
00752      * @ingroup API
00753      * @param c The character to write to the serial port
00754      */
00755     int putc(int c);
00756     #endif
00757     
00758     #if 0 // Inhereted from Serial/Stream, for documentation only
00759     /**
00760      * Function: printf
00761      *  
00762      * Write a formated string
00763      * Inhereted from Serial/Stream
00764      *
00765      * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.printf
00766      * @ingroup API
00767      * @param format A printf-style format string, followed by the variables to use in formating the string.
00768      */
00769     int printf(const char* format, ...);
00770     #endif
00771     
00772     #if 0 // Inhereted from Serial/Stream, for documentation only
00773     /**
00774      * Function: scanf
00775      *  
00776      * Read a formated string
00777      * Inhereted from Serial/Stream
00778      *
00779      * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.scanf
00780      * @ingroup API
00781      * @param format - A scanf-style format string, followed by the pointers to variables to store the results.
00782      */
00783     int scanf(const char* format, ...);
00784     #endif
00785 
00786 protected:    
00787     /**
00788      * Used to pass information to callbacks.
00789      * @ingroup INTERNALS
00790      */
00791     MODSERIAL_IRQ_INFO  callbackInfo;
00792 
00793     /**
00794      * Remove the last char placed into the rx buffer.
00795      * This is an operation that can only be performed
00796      * by an rxCallback function. To protect the buffers
00797      * this function is defined protected so that a 
00798      * regular application cannot call it directly. It 
00799      * can only be called by the public version within a
00800      * MODSERIAL_IRQ_INFO class.
00801      * @ingroup INTERNALS
00802      * @return The byte removed from the buffer.
00803      */
00804     int rxDiscardLastChar(void);    
00805             
00806 private:
00807 
00808     /**
00809      * A pointer to the UART peripheral base address being used.
00810      * @ingroup INTERNALS
00811      */
00812     void *_base;
00813     
00814     /**
00815      * The last byte to pass through the TX IRQ handler.
00816      * @ingroup INTERNALS
00817      */
00818     volatile char txc;
00819     
00820     /**
00821      * The last byte to pass through the RX IRQ handler.
00822      * @ingroup INTERNALS
00823      */
00824     volatile char rxc;
00825     
00826     /**
00827      * Pointers to the TX and RX buffers.
00828      * @ingroup INTERNALS
00829      */
00830     volatile char *buffer[2];
00831     
00832     /**
00833      * Buffer in pointers.
00834      * @ingroup INTERNALS
00835      */
00836     volatile int   buffer_in[2];
00837     
00838     /**
00839      * Buffer out pointers.
00840      * @ingroup INTERNALS
00841      */
00842     volatile int   buffer_out[2];
00843     
00844     /**
00845      * Buffer lengths.
00846      * @ingroup INTERNALS
00847      */
00848     volatile int   buffer_size[2];
00849     
00850     /**
00851      * Buffer content counters.
00852      * @ingroup INTERNALS
00853      */
00854     volatile int   buffer_count[2];
00855     
00856     /**
00857      * Buffer overflow.
00858      * @ingroup INTERNALS
00859      */
00860     volatile int   buffer_overflow[2];
00861     
00862     /**
00863      * Auto-detect character.
00864      * @ingroup INTERNALS
00865      */
00866     volatile char auto_detect_char;
00867     
00868     /**
00869      * Callback system.
00870      * @ingroup INTERNALS
00871      */
00872     MODSERIAL_callback  _isr[NumOfIrqTypes];
00873     
00874     /**
00875      * TX Interrupt Service Routine.
00876      * @ingroup INTERNALS
00877      */
00878     void isr_tx(bool doCallback);
00879     
00880     /**
00881      * TX Interrupt Service Routine stub version.
00882      * @ingroup INTERNALS
00883      */ 
00884     void isr_tx(void) { isr_tx(true); }
00885     
00886     
00887     /**
00888      * RX Interrupt Service Routine.
00889      * @ingroup INTERNALS
00890      */
00891     void isr_rx(void);
00892     
00893     /**
00894      * Disable the interrupts for this Uart.
00895      * @ingroup INTERNALS
00896      */
00897     void disableIrq(void);
00898     
00899     /**
00900      * Enable the interrupts for this Uart.
00901      * @ingroup INTERNALS
00902      */
00903     void enableIrq(void);
00904     
00905     /**
00906      * Get a character from the RX buffer
00907      * @ingroup INTERNALS
00908      * @param bool True to block (wait for input)
00909      * @return A byte from the buffer.
00910      */
00911     int __getc(bool);
00912     
00913     /**
00914      * Put a character from the TX buffer
00915      * @ingroup INTERNALS
00916      * @param bool True to block (wait for space in the TX buffer if full)
00917      * @return 0 on success
00918      */
00919     int __putc(int c, bool);
00920     
00921     /**
00922      * Function: _putc 
00923      * Overloaded virtual function.
00924      */
00925     virtual int _putc(int c) { return __putc(c, true); }
00926     
00927     /**
00928      * Function: _getc 
00929      * Overloaded virtual function.
00930      */
00931     virtual int _getc()      { return __getc(true); }
00932         
00933     /** 
00934      * Function: init
00935      * Initialize the MODSERIAL object
00936      * @ingroup INTERNALS
00937      */
00938     void init(int txSize, int rxSize);
00939     
00940     /** 
00941      * Function: flushBuffer
00942      * @ingroup INTERNALS
00943      */
00944     void flushBuffer(IrqType type);
00945 
00946     /** 
00947      * Function: resizeBuffer
00948      * @ingroup INTERNALS
00949      */
00950     int resizeBuffer(int size, IrqType type = RxIrq, bool memory_check = true);   
00951     
00952     /** 
00953      * Function: downSizeBuffer
00954      * @ingroup INTERNALS
00955      */
00956     int downSizeBuffer(int size, IrqType type, bool memory_check); 
00957     
00958     /** 
00959      * Function: upSizeBuffer
00960      * @ingroup INTERNALS
00961      */
00962     int upSizeBuffer(int size, IrqType type, bool memory_check); 
00963 
00964     /*
00965      * If MODDMA is available the compile in code to handle sending
00966      * an arbitary char buffer. Note, the parts before teh #ifdef
00967      * are declared so that MODSERIAL can access then even if MODDMA
00968      * isn't avaiable. Since MODDMA.h is only available at this point
00969      * all DMA functionality must be declared inline in the class
00970      * definition.
00971      */
00972 public:
00973 
00974     int dmaSendChannel;
00975     void *moddma_p;
00976     
00977 #ifdef MODDMA_H
00978 
00979     MODDMA_Config *config;
00980     
00981     /**
00982      * Set the "void pointer" moddma_p to be a pointer to a
00983      * MODDMA controller class instance. Used to manage the
00984      * data transfer of DMA configurations.
00985      *
00986      * @ingroup API
00987      * @param p A pointer to "the" instance of MODDMA.
00988      */
00989     void MODDMA(MODDMA *p) { moddma_p = p; }
00990     
00991     /**
00992      * Send a char buffer to the Uarts TX system
00993      * using DMA. This blocks regular library
00994      * sending.
00995      *
00996      * @param buffer A char buffer of bytes to send.
00997      * @param len The length of the buffer to send.
00998      * @param dmaChannel The DMA channel to use, defaults to 7
00999      * @return MODDMA::Status MODDMA::ok if all went ok
01000      */   
01001     int dmaSend(char *buffer, int len, int dmaChannel = 7) 
01002     {
01003         if (moddma_p == (void *)NULL) return -2;
01004         class MODDMA *dma = (class MODDMA *)moddma_p;
01005         
01006         dmaSendChannel = dmaChannel & 0x7;
01007         
01008         uint32_t conn = MODDMA::UART0_Tx;
01009         switch(_uidx) {
01010             case 0: conn = MODDMA::UART0_Tx; break;
01011             case 1: conn = MODDMA::UART1_Tx; break;
01012             case 2: conn = MODDMA::UART2_Tx; break;
01013             case 3: conn = MODDMA::UART3_Tx; break;
01014         }
01015         
01016         config = new MODDMA_Config;
01017         config
01018          ->channelNum    ( (MODDMA::CHANNELS)(dmaSendChannel & 0x7) )
01019          ->srcMemAddr    ( (uint32_t) buffer )
01020          ->transferSize  ( len )
01021          ->transferType  ( MODDMA::m2p )
01022          ->dstConn       ( conn )
01023          ->attach_tc     ( this, &MODSERIAL::dmaSendCallback )
01024          ->attach_err    ( this, &MODSERIAL::dmaSendCallback )
01025         ; // config end
01026         
01027         // Setup the configuration.
01028         if (dma->Setup(config) == 0) { 
01029             return -1;
01030         }
01031         
01032         //dma.Enable( MODDMA::Channel_0 );
01033         dma->Enable( config->channelNum() );
01034         return MODDMA::Ok ;
01035     }
01036     
01037     /**
01038      * Attach a callback to the DMA completion.
01039      *
01040      * @ingroup API
01041      * @param fptr A function pointer to call
01042      * @return this
01043      */
01044     void attach_dmaSendComplete(void (*fptr)(MODSERIAL_IRQ_INFO  *)) {  
01045         _isrDmaSendComplete.attach(fptr);         
01046     }
01047     
01048     /**
01049      * Attach a callback to the DMA completion.
01050      *
01051      * @ingroup API
01052      * @param tptr A template pointer to the calling object
01053      * @param mptr A method pointer within the object to call.
01054      * @return this
01055      */
01056     template<typename T>
01057     void attach_dmaSendComplete(T* tptr, void (T::*mptr)(MODSERIAL_IRQ_INFO  *)) {  
01058         if((mptr != NULL) && (tptr != NULL)) {
01059             _isrDmaSendComplete.attach(tptr, mptr);         
01060         }
01061     }
01062     
01063     MODSERIAL_callback  _isrDmaSendComplete;
01064     
01065 protected:    
01066     /**
01067      * Callback for dmaSend(). 
01068      */
01069     void dmaSendCallback(void) 
01070     {
01071         if (moddma_p == (void *)NULL) return;
01072         class MODDMA *dma = (class MODDMA *)moddma_p;
01073         
01074         MODDMA_Config *config = dma->getConfig();
01075         dma->haltAndWaitChannelComplete( (MODDMA::CHANNELS)config->channelNum());
01076         dma->Disable( (MODDMA::CHANNELS)config->channelNum() );
01077         if (dma->irqType() == MODDMA::TcIrq)  dma->clearTcIrq();
01078         if (dma->irqType() == MODDMA::ErrIrq) dma->clearErrIrq();
01079         dmaSendChannel = -1;
01080         _isrDmaSendComplete.call(&this->callbackInfo);
01081         delete(config);
01082     }
01083     
01084 #endif // MODDMA_H
01085 
01086 };
01087 
01088 }; // namespace AjK ends
01089 
01090 using namespace AjK;
01091 
01092 #endif