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