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.
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
Generated on Fri Jul 15 2022 13:04:34 by 1.7.2