haptics version
Fork of MODSERIAL by
Revision 18:21ef26402365, committed 2011-04-21
- Comitter:
- AjK
- Date:
- Thu Apr 21 09:20:41 2011 +0000
- Parent:
- 17:6c9b57c14868
- Child:
- 19:a158936322cc
- Commit message:
- 1.18 See ChangeLog.c
Changed in this revision
--- a/ChangeLog.c Tue Mar 08 01:42:25 2011 +0000 +++ b/ChangeLog.c Thu Apr 21 09:20:41 2011 +0000 @@ -1,5 +1,21 @@ /* $Id:$ +1.18 20 April 2011 + + * All callbacks now use MODSERIAL_callback (rather than Mbed's FunctionPointer[1] type) + to store and invoke it's callbacks. This allows MODSERIAL to pass a parameter + to callbacks. The function prototype is now void func(MODSERIAL_IRQ_INFO *q). + * Callbacks now pass a pointer to a MODSERIAL_IRQ_INFO class type. + This class holds a pointer to the MODSERIAL object that invoked the callback + thus freeing callbacks need to use the global variable of the original + MODSERIAL instance. + * MODSERIAL_IRQ_INFO also declares public functions that are protected within MODSERIAL + thus allowing certain functions to be restricted to callback context only. + * New function MODSERIAL_IRQ_INFO::rxDiscardLastChar() allows an rxCallback function + to remove the character that was just placed into the RX buffer. + + [1] http://mbed.org/users/AjK/libraries/FPointer/latest/docs/ + 1.17 08/Mar/2011 Fixed a memory leak in the DMA code. @@ -38,7 +54,7 @@ 1.10 - 23/11/2010 - * Reanme the DMA callback from attach_dma_complete() to attach_dmaSendComplete() + * Rename the DMA callback from attach_dma_complete() to attach_dmaSendComplete() 1.9 - 23/11/2010
--- a/INIT.cpp Tue Mar 08 01:42:25 2011 +0000 +++ b/INIT.cpp Thu Apr 21 09:20:41 2011 +0000 @@ -30,6 +30,8 @@ { disableIrq(); + callbackInfo.setSerial(this); + switch(_uidx) { case 0: _base = LPC_UART0; break; case 1: _base = LPC_UART1; break;
--- a/ISR_RX.cpp Tue Mar 08 01:42:25 2011 +0000 +++ b/ISR_RX.cpp Thu Apr 21 09:20:41 2011 +0000 @@ -29,7 +29,7 @@ MODSERIAL::isr_rx(void) { if (! _base || buffer_size[RxIrq] == 0 || buffer[RxIrq] == (char *)NULL) { - _isr[RxIrq].call(); + _isr[RxIrq].call(&this->callbackInfo); return; } @@ -37,9 +37,9 @@ rxc = (char)(_RBR & 0xFF); if ( MODSERIAL_RX_BUFFER_FULL ) { buffer_overflow[RxIrq] = rxc; // Oh dear, no room in buffer. - _isr[RxOvIrq].call(); - } - else { + _isr[RxOvIrq].call(&this->callbackInfo); + } + else { if (buffer[RxIrq] != (char *)NULL) { buffer[RxIrq][buffer_in[RxIrq]] = rxc; buffer_count[RxIrq]++; @@ -48,10 +48,10 @@ buffer_in[RxIrq] = 0; } } - _isr[RxIrq].call(); + _isr[RxIrq].call(&this->callbackInfo); } if (auto_detect_char == rxc) { - _isr[RxAutoDetect].call(); + _isr[RxAutoDetect].call(&this->callbackInfo); } } }
--- a/ISR_TX.cpp Tue Mar 08 01:42:25 2011 +0000 +++ b/ISR_TX.cpp Thu Apr 21 09:20:41 2011 +0000 @@ -29,7 +29,7 @@ MODSERIAL::isr_tx(bool doCallback) { if (! _base || buffer_size[TxIrq] == 0 || buffer[TxIrq] == (char *)NULL) { - _isr[TxIrq].call(); + _isr[TxIrq].call(&this->callbackInfo); return; } @@ -40,12 +40,12 @@ if (buffer_out[TxIrq] >= buffer_size[TxIrq]) { buffer_out[TxIrq] = 0; } - if (doCallback) _isr[TxIrq].call(); + if (doCallback) _isr[TxIrq].call(&this->callbackInfo); } if ( MODSERIAL_TX_BUFFER_EMPTY ) { _IER = 1; - _isr[TxEmpty].call(); + _isr[TxEmpty].call(&this->callbackInfo); } }
--- a/MODSERIAL.cpp Tue Mar 08 01:42:25 2011 +0000 +++ b/MODSERIAL.cpp Thu Apr 21 09:20:41 2011 +0000 @@ -105,5 +105,24 @@ } } +int +MODSERIAL::rxDiscardLastChar(void) +{ + // This function can only be called indirectly from + // an rxCallback function. Therefore, we know we + // just placed a char into the buffer. + char c = buffer[RxIrq][buffer_in[RxIrq]]; + + if (buffer_count[RxIrq]) { + buffer_count[RxIrq]--; + buffer_in[RxIrq]--; + if (buffer_in[RxIrq] < 0) { + buffer_in[RxIrq] = buffer_size[RxIrq] - 1; + } + } + + return (int)c; +} + }; // namespace AjK ends
--- a/MODSERIAL.h Tue Mar 08 01:42:25 2011 +0000 +++ b/MODSERIAL.h Thu Apr 21 09:20:41 2011 +0000 @@ -45,6 +45,135 @@ namespace AjK { +// Forward reference. +class MODSERIAL; + +/** + * @author Andy Kirkham + * @see http://mbed.org/cookbook/MODSERIAL + * @see example3a.cpp + * @see example3b.cpp + * @see API + * + * <b>MODSERIAL_IRQ_INFO</b> is a class used to pass information (and access to protected + * MODSERIAL functions) to IRQ callbacks. + */ +class MODSERIAL_IRQ_INFO +{ +public: + friend class MODSERIAL; + + MODSERIAL *serial; + + MODSERIAL_IRQ_INFO() { serial = 0; } + + /** rxDiscardLastChar() + * + * Remove the last char placed into the rx buffer. + * This is an operation that can only be performed + * by an rxCallback function. + * @ingroup API + * @return The byte removed from the buffer. + */ + int rxDiscardLastChar(void); + +protected: + + /** setSerial() + * + * Used internally by MODSERIAL to set the "this" pointer + * of the MODSERIAL that created this object. + * @ingroup INTERNAL + * @param A pointer to a MODSERIAL object instance. + */ + void setSerial(MODSERIAL *s) { serial = s; } +}; + +// Forward reference dummy class. +class MODSERIAL_callback_dummy; + +/** + * @author Andy Kirkham + * @see http://mbed.org/cookbook/MODSERIAL + * @see example3a.cpp + * @see example3b.cpp + * @see API + * + * <b>MODSERIAL_callback</b> is a class used to hold application callbacks that + * MODSERIAL can invoke on certain events. + */ +class MODSERIAL_callback +{ +protected: + + //! C callback function pointer. + void (*c_callback)(MODSERIAL_IRQ_INFO *); + + //! C++ callback object/method pointer (the object part). + MODSERIAL_callback_dummy *obj_callback; + + //! C++ callback object/method pointer (the method part). + void (MODSERIAL_callback_dummy::*method_callback)(MODSERIAL_IRQ_INFO *); + +public: + + /** Constructor + */ + MODSERIAL_callback() { + c_callback = 0; + obj_callback = 0; + method_callback = 0; + } + + /** attach - Overloaded attachment function. + * + * Attach a C type function pointer as the callback. + * + * Note, the callback function prototype must be:- + * @code + * void myCallbackFunction(MODSERIAL_IRQ_INFO *); + * @endcode + * @param A C function pointer to call. + */ + void attach(void (*function)(MODSERIAL_IRQ_INFO *) = 0) { c_callback = function; } + + /** attach - Overloaded attachment function. + * + * Attach a C++ type object/method pointer as the callback. + * + * Note, the callback method prototype must be:- + * @code + * public: + * void myCallbackFunction(MODSERIAL_IRQ_INFO *); + * @endcode + * @param A C++ object pointer. + * @param A C++ method within the object to call. + */ + template<class T> + void attach(T* item, void (T::*method)(MODSERIAL_IRQ_INFO *)) { + obj_callback = (MODSERIAL_callback_dummy *)item; + method_callback = (void (MODSERIAL_callback_dummy::*)(MODSERIAL_IRQ_INFO *))method; + } + + /** call - Overloaded callback initiator. + * + * call the callback function. + * + * @param uint32_t The value to pass to the callback. + * @return uint32_t The value the callback returns. + */ + void call(MODSERIAL_IRQ_INFO *arg) { + if (c_callback != 0) { + (*c_callback)(arg); + } + else { + if (obj_callback != 0 && method_callback != 0) { + (obj_callback->*method_callback)(arg); + } + } + } +}; + /** * @author Andy Kirkham * @see http://mbed.org/cookbook/MODSERIAL @@ -113,6 +242,9 @@ { public: + // Allow instances of MODSERIAL_IRQ_INFO to use protected properties and methods. + friend class MODSERIAL_IRQ_INFO; + //! A copy of the Serial parity enum /** @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.format */ enum Parity { @@ -231,7 +363,7 @@ * @param fptr A pointer to a void function, or 0 to set as none * @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty) */ - void attach(void (*fptr)(void), IrqType type = RxIrq) { _isr[type].attach(fptr); } + void attach(void (*fptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) { _isr[type].attach(fptr); } /** * Function: attach @@ -293,8 +425,8 @@ * @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty) */ template<typename T> - void attach(T* tptr, void (T::*mptr)(void), IrqType type = RxIrq) { - if((mptr != NULL) && (tptr != NULL)) { + void attach(T* tptr, uint32_t (T::*mptr)(uint32_t), IrqType type = RxIrq) { + if((mptr != 0) && (tptr != 0)) { _isr[type].attach(tptr, mptr); } } @@ -303,15 +435,15 @@ * @see attach * @ingroup API */ - void connect(void (*fptr)(void), IrqType type = RxIrq) { _isr[RxIrq].attach(fptr); } + void connect(void (*fptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) { _isr[RxIrq].attach(fptr); } /** * @see attach * @ingroup API */ template<typename T> - void connect(T* tptr, void (T::*mptr)(void), IrqType type = RxIrq) { - if((mptr != NULL) && (tptr != NULL)) { + void connect(T* tptr, void (T::*mptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) { + if((mptr != 0) && (tptr != 0)) { _isr[type].attach(tptr, mptr); } } @@ -646,8 +778,28 @@ */ int scanf(const char* format, ...); #endif + +protected: + /** + * Used to pass information to callbacks. + * @ingroup INTERNALS + */ + MODSERIAL_IRQ_INFO callbackInfo; + + /** + * Remove the last char placed into the rx buffer. + * This is an operation that can only be performed + * by an rxCallback function. To protect the buffers + * this function is defined protected so that a + * regular application cannot call it directly. It + * can only be called by the public version within a + * MODSERIAL_IRQ_INFO class. + * @ingroup INTERNALS + * @return The byte removed from the buffer. + */ + int rxDiscardLastChar(void); -protected: +private: /** * A pointer to the UART peripheral base address being used. @@ -713,7 +865,7 @@ * Callback system. * @ingroup INTERNALS */ - FunctionPointer _isr[NumOfIrqTypes]; + MODSERIAL_callback _isr[NumOfIrqTypes]; /** * TX Interrupt Service Routine. @@ -745,7 +897,7 @@ * @ingroup INTERNALS */ void enableIrq(void); - + /** * Get a character from the RX buffer * @ingroup INTERNALS @@ -885,7 +1037,7 @@ * @param fptr A function pointer to call * @return this */ - void attach_dmaSendComplete(void (*fptr)(void)) { + void attach_dmaSendComplete(void (*fptr)(MODSERIAL_IRQ_INFO *)) { _isrDmaSendComplete.attach(fptr); } @@ -898,13 +1050,13 @@ * @return this */ template<typename T> - void attach_dmaSendComplete(T* tptr, void (T::*mptr)(void)) { + void attach_dmaSendComplete(T* tptr, void (T::*mptr)(MODSERIAL_IRQ_INFO *)) { if((mptr != NULL) && (tptr != NULL)) { _isrDmaSendComplete.attach(tptr, mptr); } } - FunctionPointer _isrDmaSendComplete; + MODSERIAL_callback _isrDmaSendComplete; protected: /** @@ -921,7 +1073,7 @@ if (dma->irqType() == MODDMA::TcIrq) dma->clearTcIrq(); if (dma->irqType() == MODDMA::ErrIrq) dma->clearErrIrq(); dmaSendChannel = -1; - _isrDmaSendComplete.call(); + _isrDmaSendComplete.call(&this->callbackInfo); delete(config); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL_IRQ_INFO.cpp Thu Apr 21 09:20:41 2011 +0000 @@ -0,0 +1,38 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + @file MODSERIAL_CB.h + @author Andy Kirkham +*/ + +#include "MODSERIAL.h" + +namespace AjK { + +int +MODSERIAL_IRQ_INFO::rxDiscardLastChar(void) +{ + if (!serial) return -1; + + return serial->rxDiscardLastChar(); +} + +}; // namespace AjK ends
--- a/PUTC.cpp Tue Mar 08 01:42:25 2011 +0000 +++ b/PUTC.cpp Thu Apr 21 09:20:41 2011 +0000 @@ -60,7 +60,7 @@ } else if( MODSERIAL_TX_BUFFER_FULL ) { buffer_overflow[TxIrq] = c; // Oh dear, no room in buffer. - _isr[TxOvIrq].call(); + _isr[TxOvIrq].call(&this->callbackInfo); return -1; } _IER &= ~2;
--- a/example1.cpp Tue Mar 08 01:42:25 2011 +0000 +++ b/example1.cpp Thu Apr 21 09:20:41 2011 +0000 @@ -33,18 +33,18 @@ // This function is called when a character goes from the TX buffer // to the Uart THR FIFO register. -void txCallback(void) { +void txCallback(MODSERIAL_IRQ_INFO *q) { led2 = !led2; } // This function is called when TX buffer goes empty -void txEmpty(void) { +void txEmpty(MODSERIAL_IRQ_INFO *q) { led2 = 0; pc.puts(" Done. "); } // This function is called when a character goes into the RX buffer. -void rxCallback(void) { +void rxCallback(MODSERIAL_IRQ_INFO *q) { led3 = !led3; pc.putc(uart.getc()); }
--- a/example2.cpp Tue Mar 08 01:42:25 2011 +0000 +++ b/example2.cpp Thu Apr 21 09:20:41 2011 +0000 @@ -99,9 +99,11 @@ char messageBufferOutgoing[MESSAGE_BUFFER_SIZE]; bool messageReceived; -void messageReceive(void) { - messageSystem.move(messageBufferIncoming, MESSAGE_BUFFER_SIZE); +void messageReceive(MODSERIAL_IRQ_INFO *q) { + MODSERIAL *sys = q->serial; + sys->move(messageBufferIncoming, MESSAGE_BUFFER_SIZE); messageReceived = true; + return 0; } void messageProcess(void) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/example3a.cpp Thu Apr 21 09:20:41 2011 +0000 @@ -0,0 +1,83 @@ +/* + Copyright (c) 2011 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + @file example3.cpp + @purpose Demos a simple filter. + @version see ChangeLog.c + @author Andy Kirkham +*/ + +/* + This example shows how to use the new callback system. In the old system + Mbed's FunctionPointer[1] type was used to store abd make calls to callbacks. + However, that limits the callback function prototype to void func(void); + which means we cannot pass parameters. + + This latest version of MODSERIAL now uses its own callback object. This allows + the passing of a pointer to a class that holds information about the MODSERIAL + object making the callback. As of version 1.18 one critcal piece of information + is passed, a pointer to the MODSERIAL object. This allows callbacks to use the + MODSERIAL functions and data. + + Additionally, since MODSERIAL and the callback parameter class MODSERIAL_IRQ_INFO + are friends, MODSERIAL_IRQ_INFO can access the protected functions of MODSERIAL. + This is used to ensure functions that can only be called during a callback + can be invoked from a callback. + + [1] http://mbed.org/projects/libraries/svn/mbed/trunk/FunctionPointer.h +*/ + +#ifdef COMPILE_EXAMPLE3_CODE_MODSERIAL + +#include "mbed.h" +#include "MODSERIAL.h" + +DigitalOut led1(LED1); + +MODSERIAL pc(USBTX, USBRX); + +// The following callback is defined in example3b.cpp +//! @see example3b.cpp +void rxCallback(MODSERIAL_IRQ_INFO *info); + +int main() { + + int life_counter = 0; + + pc.baud(115200); + + pc.attach(&rxCallback, MODSERIAL::RxIrq); + + while(1) { + // Echo back any chars we get except 'A' which is filtered by the rxCallback. + if (pc.readable()) { + pc.putc(pc.getc()); + } + + // Toggle LED1 every so often to show we are alive. + if (life_counter++ == 1000000) { + life_counter = 0; + led1 = !led1; + } + } +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/example3b.cpp Thu Apr 21 09:20:41 2011 +0000 @@ -0,0 +1,78 @@ +/* + Copyright (c) 2011 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + @file example3b.cpp + @purpose Demos a simple filter. + @version see ChangeLog.c + @author Andy Kirkham +*/ + +/* + This example shows how to use the new callback system. In the old system + Mbed's FunctionPointer[1] type was used to store abd make calls to callbacks. + However, that limits the callback function prototype to void func(void); + which means we cannot pass parameters. + + This latest version of MODSERIAL now uses its own callback object. This allows + the passing of a pointer to a class that holds information about the MODSERIAL + object making the callback. As of version 1.18 one critcal piece of information + is passed, a pointer to the MODSERIAL object. This allows callbacks to use the + MODSERIAL functions and data. + + Additionally, since MODSERIAL and the callback parameter class MODSERIAL_IRQ_INFO + are friends, MODSERIAL_IRQ_INFO can access the protected functions of MODSERIAL. + This is used to ensure functions that can only be called during a callback + can be invoked from a callback. + + [1] http://mbed.org/projects/libraries/svn/mbed/trunk/FunctionPointer.h +*/ + + +#ifdef COMPILE_EXAMPLE3_CODE_MODSERIAL + +#include "mbed.h" +#include "MODSERIAL.h" + +void rxCallback(MODSERIAL_IRQ_INFO *info) { + + // Get the pointer to our MODSERIAL object that invoked this callback. + MODSERIAL *pc = info->serial; + + // info->serial points at the MODSERIAL instance so we can use it to call + // any of the public MODSERIAL functions that are normally available. So + // there's now no need to use the global version (pc in our case) inside + // callback functions. + char c = pc->rxGetLastChar(); // Where local pc variable is a pointer to the global MODSERIAL pc object. + + // The following is rather daft but demos the point. + // Don't allow the letter "A" go into the RX buffer. + // Basically acts as a filter to remove the letter "A" + // if it goes into the RX buffer. + if (c == 'A') { + // Note, we call the MODSERIAL_IRQ_INFO::rxDiscardLastChar() public function which + // is permitted access to the protected version of MODSERIAL::rxDiscardLastChar() + // within MODSERIAL (because they are friends). This ensures rxDiscardLastChar() + // can only be called within an rxCallback function. + info->rxDiscardLastChar(); + } +} + +#endif