System Management code
Dependencies: mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP
Fork of SystemManagement by
Revision 31:7eaa5e881b56, committed 2014-11-14
- Comitter:
- pspatel321
- Date:
- Fri Nov 14 06:05:59 2014 +0000
- Parent:
- 30:91af74a299e1
- Child:
- 32:e70407021ad2
- Commit message:
- Mostly working. Wrote CAN in/out code. Xbee still needs work. My guess is that MODDMA breaks when used with RTOS.
Changed in this revision
--- a/IOobjects/CAN_Filter_LUT.h Thu Nov 13 10:53:10 2014 +0000 +++ b/IOobjects/CAN_Filter_LUT.h Fri Nov 14 06:05:59 2014 +0000 @@ -39,6 +39,8 @@ // STANDARD ID RANGES - CAN CONTROLLER 2 //( 0xLOWERBOUND & STDMASK | 1<<13) << 16 | ( 0xUPPERBOUND & STDMASK | 1<<13), lower/upperbounds are inclusive +//( 0xLOWERBOUND & STDMASK | 1<<13) << 16 | ( 0xUPPERBOUND & STDMASK | 1<<13), lower/upperbounds are inclusive + }; const uint32_t AF_LUT_EEI[] = {
--- a/IOobjects/CAN_RxIDs.h Thu Nov 13 10:53:10 2014 +0000 +++ b/IOobjects/CAN_RxIDs.h Fri Nov 14 06:05:59 2014 +0000 @@ -2,5 +2,14 @@ #define CAN_RXIDS_H // Receive IDs +#define FAN_CONTROL_ID 0x480 +#define PUMP_CONTROL_ID 0x481 +#define DCDC_CONTROL_ID 0x482 + +#define AMS_RELAYS_ID 0x30E + +#define GLVBAT_CLEARSOC_ID 0x490 +#define GLVBAT_CLEARAH_ID 0x491 +#define GLVBAT_SETCAPAC_ID 0x492 #endif \ No newline at end of file
--- a/IOobjects/CAN_TxIDs.h Thu Nov 13 10:53:10 2014 +0000 +++ b/IOobjects/CAN_TxIDs.h Fri Nov 14 06:05:59 2014 +0000 @@ -1,6 +1,36 @@ #ifndef CAN_TXIDS_H #define CAN_TXIDS_H +// Transmit IDs - System Mgmt Specific +// Operating diagnostics +#define SYS_ERROR_ID 0x400 // Error frame - critical errors that require shutdown +#define SYS_XBEE1_ID 0x401 // Message in/out counter for xbee1 +#define SYS_XBEE2_ID 0x402 // Message in/out counter for xbee2 +#define SYS_TEMP_ID 0x403 // Internal temperature of the glv battery chargerFET +// GLV Battery +#define SYS_GLV_CURRENT_ID 0x410 // GLV battery current +#define SYS_GLV_CAPACITY_ID 0x411 // GLV battery capacity setting +#define SYS_GLV_AH_ID 0x412 // GLV battery amphours +#define SYS_GLV_SOC_ID 0x413 // GLV battery SOC + +// DC-DC Converter +#define SYS_DCDC_CURRENT_ID 0x420 // DC-DC current +#define SYS_DCDC_STATUS_ID 0x421 // DC-DC status byte + +// PWM Channels +#define SYS_PWM_FAN_ID 0x430 // FAN1 actual pwm +#define SYS_PWM_PUMP_ID 0x431 // PUMP1 actual pwm + +// IMD +#define SYS_IMD_STATUS_ID 0x440 // IMD status byte +#define SYS_IMD_RESIST_ID 0x441 // IMD resistance measurement + +// Latch Supervisor states +#define SYS_IMD_LATCH_ID 0x450 // IMD Latch circuit error byte +#define SYS_AMS_LATCH_ID 0x451 // AMS Latch circuit error byte + +// Shutdown Switches +#define SYS_SWITCHES_ID 0x460 // Shutdown Switch State #endif \ No newline at end of file
--- a/IOobjects/IOobjects.cpp Thu Nov 13 10:53:10 2014 +0000 +++ b/IOobjects/IOobjects.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -19,14 +19,16 @@ CoulombCounter glvBat(p19, 10); // Coulomb counter battery monitor for GLV Battery (CURRENT SENSE PIN, INTEGRATION TIME) DC_DC dcdc(p18, p20, p26, p25, p24, p23, 0.01, 1); // DC-DC converter & high-current load control (CONTROL PIN< CURRENT SENSE PIN, FAN1 PIN, FAN2 PIN, PUMP1 PIN, PUMP2 PIN, PWM PERIOD (sec), FULL-SCALE SLEW (sec)) IMD imd(p1_26); // IMD PWM sense channel to read status and resistance (IMD PWM PIN) -LatchMonitor AMSlatch(p0_18, p0_22, 5000); // Supervisor for AMS hardware latch/reset circuit (OK PIN, FAULT PIN, STARTUP DELAY (ms)) -LatchMonitor IMDlatch(p0_17, p0_21, 5000); // Supervisor for IMD hardware latch/reset circuit (OK PIN, FAULT PIN, STARTUP DELAY (ms)) +LatchMonitor AMSlatch(p0_18, p0_22, 15000); // Supervisor for AMS hardware latch/reset circuit (OK PIN, FAULT PIN, STARTUP DELAY (ms)) +LatchMonitor IMDlatch(p0_17, p0_21, 15000); // Supervisor for IMD hardware latch/reset circuit (OK PIN, FAULT PIN, STARTUP DELAY (ms)) MODSERIAL pc(USBTX, USBRX); // Serial to computer for diagnostics Temperature internalTmp(&NXFT15XH103_TABLE, p15); // Temperature conversion look-up table for internal temperature on the GLV bat charger FET (TABLE PTR, PIN) PollSwitch switches(sw, sizeof(sw)/sizeof(sw[0])); // Shutdown switch sense pins (SWITCH PIN ARRAY, NUM PINS) Watchdog wdt(0.25); // Watchdog timer (TIMEOUT (sec)) -Xbee xbee1(p9, p10, 250000, 1000, '\n'); // Software buffered Xbee 1 of 2 for wireless comms (TX, RX, BAUD, BUFFERSIZE, DELIM CHAR) -Xbee xbee2(p9, p10, 250000, 1000, '\n'); // Software buffered Xbee 2 of 2 for wireless comms (TX, RX, BAUD, BUFFERSIZE, DELIM CHAR) +//Xbee xbee1(p9, p10, 250000, 1000, '\n'); // Software buffered Xbee 1 of 2 for wireless comms (TX, RX, BAUD, BUFFERSIZE, DELIM CHAR) +//Xbee xbee2(p13, p14, 250000, 1000, '\n'); // Software buffered Xbee 2 of 2 for wireless comms (TX, RX, BAUD, BUFFERSIZE, DELIM CHAR) +XbeeRelay xbee; + DigitalOut extras[] = {(p16), (p17)}; // Unused analog pins driven low Inputs data; CANinputs CANdata; \ No newline at end of file
--- a/IOobjects/IOobjects.h Thu Nov 13 10:53:10 2014 +0000 +++ b/IOobjects/IOobjects.h Fri Nov 14 06:05:59 2014 +0000 @@ -13,6 +13,7 @@ #include "Temperature.h" #include "Watchdog.h" #include "Xbee.h" +#include "XbeeRelay.h" extern CANBuffer can; extern CoulombCounter glvBat; @@ -24,8 +25,7 @@ extern PollSwitch switches; extern Temperature internalTmp; extern Watchdog wdt; -extern Xbee xbee1; -extern Xbee xbee2; +extern XbeeRelay xbee; // Shared data updated by producer threads class Inputs {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODDMA.lib Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/AjK/code/MODDMA/#97a16bf2ff43
--- a/Libs/MODSERIAL.lib Thu Nov 13 10:53:10 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/AjK/code/MODSERIAL/#ae0408ebdd68
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODSERIAL/ChangeLog.c Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,177 @@ +/* $Id:$ + +1.25 8th January 2013 + + * Bring back into line with MBed libraries. + * Credits: + Erik Olieman : http://mbed.org/users/Sissors/code/MODSERIAL/rev/3ba4341d74d6 + Erik Olieman : http://mbed.org/users/Sissors/code/MODSERIAL/rev/a469aa702bab + + +1.24 6th Dec 2012 + + * Beta release for new Mbed library. + +1.23 25th July 2012 + + * LPC1768 code as was. This release includes "alpha" support for the LPC11U24 + +1.22 19th April 2012 + + * http://mbed.org/forum/bugs-suggestions/topic/2936/ + * Bug fix, protect important buffer pointers from IRQ corruption. + * Credits: + Anthony Wieser http://mbed.org/users/WieserSoftwareLtd/ for the fix. + BlazeX http://mbed.org/users/BlazeX/ for the alert that a fix was needed! + +1.21 10 May 2011 + + * http://mbed.org/forum/mbed/topic/2264 + +1.20 26 April 2011 + + * Bug fix, not blocking on transmit + by Erik Petrich, http://mbed.org/forum/bugs-suggestions/topic/2200 + +1.19 20 April 2011 + + * Fixed some doxygen comment bugs. + +1.18 20 April 2011 + + * All callbacks now use MODSERIAL_callback (rather than Mbed's FunctionPointer[1] type) + to store and invoke it's callbacks. This allows MODSERIAL to pass a parameter + to callbacks. The function prototype is now void func(MODSERIAL_IRQ_INFO *q). + * Callbacks now pass a pointer to a MODSERIAL_IRQ_INFO class type. + This class holds a pointer to the MODSERIAL object that invoked the callback + thus freeing callbacks need to use the global variable of the original + MODSERIAL instance. + * MODSERIAL_IRQ_INFO also declares public functions that are protected within MODSERIAL + thus allowing certain functions to be restricted to callback context only. + * New function MODSERIAL_IRQ_INFO::rxDiscardLastChar() allows an rxCallback function + to remove the character that was just placed into the RX buffer. + + [1] http://mbed.org/users/AjK/libraries/FPointer/latest/docs/ + +1.17 08/Mar/2011 + Fixed a memory leak in the DMA code. + +1.16 - 12 Feb 2011 + + * Missed one, doh! + +1.15 - 12 Feb 2011 + + * Fixed some typos. + +1.14 - 7 Feb 2011 + + * Fixed a bug in __putc() that caused the output buffer pointer to + become corrupted. + +1.13 - 20/01/2011 + + * Added extra documentation. + * Fixed some typos. + +1.12 - 20/01/2011 + + * Added new "autoDetectChar()" function. To use:- + 1st: Add a callback to invoke when the char is detected:- + .attach(&detectedChar, MODSERIAL::RxAutoDetect); + 2nd: Send the char to detect. + .autoDectectChar('\n'); + Whenever that char goes into the RX buffer your callback will be invoked. + Added example2.cpp to demo a simple messaging system using this auto feature. + + +1.11 - 23/11/2010 + + * Fixed a minor issue with 1.10 missed an alteration of name change. + +1.10 - 23/11/2010 + + * Rename the DMA callback from attach_dma_complete() to attach_dmaSendComplete() + +1.9 - 23/11/2010 + + * Added support for DMA sending of characters. Required is + the MODDMA library module:- + http://mbed.org/users/AjK/libraries/MODDMA/latest + See example_dma.cpp for more information. + +1.8 - 22/11/2010 + + * Added code so that if a buffer is set to zero length then + MODSERIAL defaults to just using the FIFO for that stream + thus making the library "fall back" to teh same operation + that the Mbed Serial library performs. + * Removed dmaSend() function that should have been removed + at 1.7 + +1.7 - 21/11/2010 + + * Remove the DMA enum from MODSERIAL.h as it's not currently + ready for release. + * Added page doxygen comments. + +1.6 - 21/11/2010 + + * Version 1.5 solved a blocking problem on putc() when called + from another ISR. However, isr_tx() invokes a callback of it's + own when a byte is tranferred from TX buffer to TX FIFO. User + programs may interpret that as an IRQ callback. That's an ISR + call from within an existing ISR which is not good. So the + TxIrq callback from isr_tx is now conditional. It will only + be called when isr_tx() is actually within it's own ISR and + not when called from alternate ISR handlers. + +1.5 - 21/11/2010 + + * Calling putc() (or any derived function that uses it like + printf()) while inside an interrupt service routine can + cause the system to lock up if the TX buffer is full. This + is because bytes are only transferred from the TX buffer to + the TX FIFO via the TX ISR. If we are, say in an RX ISR already, + then the TX ISR will never trigger. The TX buffer stays full and + there is never space to putc() the byte. So, while putc() blocks + waiting for space it calls isr_tx() to ensure if TX FIFO space + becomes available it will move bytes from the TX buffer to TX + FIFO thus removing the blocking condition within putc(). + +1.4 - 21/11/2010 + + * Removed all the new DMA code. I wish mbed.org had proper SVN + versioning, I'm use to working in HEAD and BRANCHES after I've + released a project. Getting bug reports in current releases + while trying to dev new code is hard to manage without source + control of some type! + +1.3 - 21/11/2010 + + * Fixed a macro problem with txIsBusy() + * Started adding code to use "block data" sending using DMA + * Removed #include "IOMACROS.h" + +1.2 - 21/11/2010 + + * Removed unsed variables from flushBuffer() + * Fixed a bug where both RX AND TX fifos are cleared/reset + when just TX OR RX should be cleared. + * Fixed a bug that cleared IIR when in fact it should be left + alone so that any pending interrupt after flush is handled. + * Merged setBase() into init() as it wasn't required anywhere else. + * Changed init() to enforce _uidx is set by Serial to define the _base + address of the Uart in use. + +1.1 - 20/11/2010 + + * Added this file + * Removed cruft from GETC.cpp + * "teh" should be "the", why do my fingers do that? + +1.0 - 20/11/2010 + + * First release. + +*/ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODSERIAL/FLUSH.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,47 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +void +MODSERIAL::flushBuffer(IrqType type) +{ + uint32_t ier = _IER; + switch(type) { + case TxIrq: _IER &= ~(1UL << 1); break; + case RxIrq: _IER &= ~(1UL << 0); break; + } + buffer_in[type] = 0; + buffer_out[type] = 0; + buffer_count[type] = 0; + buffer_overflow[type] = 0; + switch(type) { + case TxIrq: _FCR = MODSERIAL_FIFO_TX_RESET; break; + case RxIrq: _FCR = MODSERIAL_FIFO_RX_RESET; break; + } + _IER = ier; +} + +}; // namespace AjK ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODSERIAL/GETC.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,65 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +int +MODSERIAL::__getc(bool block) +{ + // If no buffer is in use fall back to standard RX FIFO usage. + // Note, we must block in this case and ignore bool "block" + // so as to maintain compat with Mbed Serial. + if (buffer_size[RxIrq] == 0 || buffer[RxIrq] == (char *)NULL) { + while(! MODSERIAL_RBR_HAS_DATA ) ; + return (int)(_RBR & 0xFF); + } + + if (block) { while ( MODSERIAL_RX_BUFFER_EMPTY ) ; } // Blocks. + else if ( MODSERIAL_RX_BUFFER_EMPTY ) return -1; + + int c = buffer[RxIrq][buffer_out[RxIrq]]; + buffer_out[RxIrq]++; + if (buffer_out[RxIrq] >= buffer_size[RxIrq]) { + buffer_out[RxIrq] = 0; + } + + // If we have made space in the RX Buffer then copy over + // any characters in the RX FIFO that my reside there. + // Temporarily disable the RX IRQ so that we do not re-enter + // it under interrupts. + if ( ! MODSERIAL_RX_BUFFER_FULL ) { + uint32_t ier = _IER; + _IER &= ~(1UL << 0); + isr_rx(); + _IER = ier; + } + + __disable_irq(); + buffer_count[RxIrq]--; + __enable_irq(); + return c; +} + +}; // namespace AjK ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODSERIAL/INIT.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,81 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + + +namespace AjK { + +void +MODSERIAL::init( int txSize, int rxSize, PinName rx ) +{ + disableIrq(); + + callbackInfo.setSerial(this); + +#ifdef __LPC11UXX_H__ + + _base = LPC_USART; + +#else + switch( _serial.index ) { + case 0: _base = LPC_UART0; break; + case 1: _base = LPC_UART1; break; + case 2: _base = LPC_UART2; break; + case 3: _base = LPC_UART3; break; + default: _base = NULL; break; + } +#endif + + dmaSendChannel = -1; + moddma_p = (void *)NULL; + + if ( _base != NULL ) { + buffer_size[RxIrq] = rxSize; + buffer[RxIrq] = rxSize > 0 ? (char *)malloc(buffer_size[RxIrq]) : (char *)NULL; + buffer_in[RxIrq] = 0; + buffer_out[RxIrq] = 0; + buffer_count[RxIrq] = 0; + buffer_overflow[RxIrq] = 0; + Serial::attach( this, &MODSERIAL::isr_rx, Serial::RxIrq ); + + buffer_size[TxIrq] = txSize; + buffer[TxIrq] = txSize > 0 ? (char *)malloc(buffer_size[TxIrq]) : (char *)NULL; + buffer_in[TxIrq] = 0; + buffer_out[TxIrq] = 0; + buffer_count[TxIrq] = 0; + buffer_overflow[TxIrq] = 0; + Serial::attach( this, &MODSERIAL::isr_tx, Serial::TxIrq ); + } + else { + error("MODSERIAL must have a defined UART to function."); + } + + _FCR = MODSERIAL_FIFO_ENABLE | MODSERIAL_FIFO_RX_RESET | MODSERIAL_FIFO_TX_RESET; + + auto_detect_char = 0; + + enableIrq(); +} + +}; // namespace AjK ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODSERIAL/ISR_RX.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,60 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +void +MODSERIAL::isr_rx(void) +{ + if (! _base || buffer_size[RxIrq] == 0 || buffer[RxIrq] == (char *)NULL) { + _isr[RxIrq].call(&this->callbackInfo); + return; + } + + while( MODSERIAL_RBR_HAS_DATA ) { + rxc = (char)(_RBR & 0xFF); + if ( MODSERIAL_RX_BUFFER_FULL ) { + buffer_overflow[RxIrq] = rxc; // Oh dear, no room in buffer. + _isr[RxOvIrq].call(&this->callbackInfo); + } + else { + if (buffer[RxIrq] != (char *)NULL) { + buffer[RxIrq][buffer_in[RxIrq]] = rxc; + buffer_count[RxIrq]++; + buffer_in[RxIrq]++; + if (buffer_in[RxIrq] >= buffer_size[RxIrq]) { + buffer_in[RxIrq] = 0; + } + } + _isr[RxIrq].call(&this->callbackInfo); + } + if (auto_detect_char == rxc) { + _isr[RxAutoDetect].call(&this->callbackInfo); + } + } +} + +}; // namespace AjK ends +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODSERIAL/ISR_TX.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,54 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +void +MODSERIAL::isr_tx(bool doCallback) +{ + if (! _base || buffer_size[TxIrq] == 0 || buffer[TxIrq] == (char *)NULL) { + _isr[TxIrq].call(&this->callbackInfo); + return; + } + + while (! MODSERIAL_TX_BUFFER_EMPTY && MODSERIAL_THR_HAS_SPACE ) { + _THR = txc = (uint8_t)(buffer[TxIrq][buffer_out[TxIrq]]); + buffer_count[TxIrq]--; + buffer_out[TxIrq]++; + if (buffer_out[TxIrq] >= buffer_size[TxIrq]) { + buffer_out[TxIrq] = 0; + } + if (doCallback) _isr[TxIrq].call(&this->callbackInfo); + } + + if ( MODSERIAL_TX_BUFFER_EMPTY ) { + _IER = 1; + _isr[TxEmpty].call(&this->callbackInfo); + } +} + +}; // namespace AjK ends + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODSERIAL/MACROS.h Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,70 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef MODSERIAL_MACROS_H +#define MODSERIAL_MACROS_H + +#define MODSERIAL_RBR 0x00 +#define MODSERIAL_THR 0x00 +#define MODSERIAL_DLL 0x00 +#define MODSERIAL_IER 0x04 +#define MODSERIAL_DML 0x04 +#define MODSERIAL_IIR 0x08 +#define MODSERIAL_FCR 0x08 +#define MODSERIAL_LCR 0x0C +#define MODSERIAL_LSR 0x14 +#define MODSERIAL_SCR 0x1C +#define MODSERIAL_ACR 0x20 +#define MODSERIAL_ICR 0x24 +#define MODSERIAL_FDR 0x28 +#define MODSERIAL_TER 0x30 + +#define MODSERIAL_LSR_RDR (1UL << 0) +#define MODSERIAL_LSR_OE (1UL << 1) +#define MODSERIAL_LSR_PE (1UL << 2) +#define MODSERIAL_LSR_FE (1UL << 3) +#define MODSERIAL_LSR_BR (1UL << 4) +#define MODSERIAL_LSR_THRE (1UL << 5) +#define MODSERIAL_LSR_TEMT (1UL << 6) +#define MODSERIAL_LSR_RXFE (1UL << 7) + +#define MODSERIAL_FIFO_ENABLE 1 +#define MODSERIAL_FIFO_RX_RESET 2 +#define MODSERIAL_FIFO_TX_RESET 4 + +#define _RBR *((char *)_base+MODSERIAL_RBR) +#define _THR *((char *)_base+MODSERIAL_THR) +#define _IIR *((char *)_base+MODSERIAL_IIR) +#define _IER *((char *)_base+MODSERIAL_IER) +#define _LSR *((char *)_base+MODSERIAL_LSR) +#define _FCR *((char *)_base+MODSERIAL_FCR) + +#define MODSERIAL_TX_BUFFER_EMPTY (buffer_count[TxIrq]==0) +#define MODSERIAL_RX_BUFFER_EMPTY (buffer_count[RxIrq]==0) +#define MODSERIAL_TX_BUFFER_FULL (buffer_count[TxIrq]==buffer_size[TxIrq]) +#define MODSERIAL_RX_BUFFER_FULL (buffer_count[RxIrq]==buffer_size[RxIrq]) + +#define MODSERIAL_THR_HAS_SPACE ((int)_LSR&MODSERIAL_LSR_THRE) +#define MODSERIAL_TEMT_IS_EMPTY ((int)_LSR&MODSERIAL_LSR_TEMT) +#define MODSERIAL_RBR_HAS_DATA ((int)_LSR&MODSERIAL_LSR_RDR) + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODSERIAL/MODSERIAL.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,137 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + @file MODSERIAL.h + @purpose Extends Serial to provide fully buffered IO + @version 1.6 + @date Nov 2010 + @author Andy Kirkham +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +MODSERIAL::MODSERIAL( PinName tx, PinName rx, const char* name ) : Serial( tx, rx, name ) +{ + init( MODSERIAL_DEFAULT_TX_BUFFER_SIZE, MODSERIAL_DEFAULT_RX_BUFFER_SIZE, rx ); +} + +MODSERIAL::MODSERIAL( PinName tx, PinName rx, int bufferSize, const char* name ) : Serial( tx, rx, name ) +{ + init( bufferSize, bufferSize, rx ); +} + +MODSERIAL::MODSERIAL( PinName tx, PinName rx, int txSize, int rxSize, const char* name ) : Serial( tx, rx, name ) +{ + init( txSize, rxSize, rx ); +} + +MODSERIAL::~MODSERIAL() +{ + disableIrq(); + if ( buffer[0] != NULL) free((char *)buffer[0] ); + if ( buffer[1] != NULL) free((char *)buffer[1] ); +} + +bool +MODSERIAL::txBufferFull( void ) +{ + return MODSERIAL_TX_BUFFER_FULL; +} + +bool +MODSERIAL::rxBufferFull( void ) +{ + return MODSERIAL_RX_BUFFER_FULL; +} + +bool +MODSERIAL::txBufferEmpty( void ) +{ + return MODSERIAL_TX_BUFFER_EMPTY; +} + +bool +MODSERIAL::rxBufferEmpty( void ) +{ + return MODSERIAL_RX_BUFFER_EMPTY; +} + +bool +MODSERIAL::txIsBusy( void ) +{ + return ( _LSR & ( 3UL << 5 ) == 0 ) ? true : false; +} + +void +MODSERIAL::disableIrq( void ) +{ + +#ifdef __LPC11UXX_H__ + NVIC_DisableIRQ( UART_IRQn ); +#else + switch( _serial.index ) { + case 0: NVIC_DisableIRQ( UART0_IRQn ); break; + case 1: NVIC_DisableIRQ( UART1_IRQn ); break; + case 2: NVIC_DisableIRQ( UART2_IRQn ); break; + case 3: NVIC_DisableIRQ( UART3_IRQn ); break; + } +#endif +} + +void +MODSERIAL::enableIrq(void) +{ +#ifdef __LPC11UXX_H__ + NVIC_EnableIRQ( UART_IRQn ); +#else + switch( _serial.index ) { + case 0: NVIC_EnableIRQ( UART0_IRQn ); break; + case 1: NVIC_EnableIRQ( UART1_IRQn ); break; + case 2: NVIC_EnableIRQ( UART2_IRQn ); break; + case 3: NVIC_EnableIRQ( UART3_IRQn ); break; + } +#endif +} + +int +MODSERIAL::rxDiscardLastChar( void ) +{ + // This function can only be called indirectly from + // an rxCallback function. Therefore, we know we + // just placed a char into the buffer. + char c = buffer[RxIrq][buffer_in[RxIrq]]; + + if (buffer_count[RxIrq]) { + buffer_count[RxIrq]--; + buffer_in[RxIrq]--; + if (buffer_in[RxIrq] < 0) { + buffer_in[RxIrq] = buffer_size[RxIrq] - 1; + } + } + + return (int)c; +} + + +}; // namespace AjK ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODSERIAL/MODSERIAL.h Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,1089 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + @file MODSERIAL.h + @purpose Extends Serial to provide fully buffered IO + @version see ChangeLog.c + @date Nov 2010 + @author Andy Kirkham +*/ + +#ifndef MODSERIAL_H +#define MODSERIAL_H + +/** @defgroup API The MODSERIAL API */ +/** @defgroup MISC Misc MODSERIAL functions */ +/** @defgroup INTERNALS MODSERIAL Internals */ + +#ifndef MODSERIAL_DEFAULT_RX_BUFFER_SIZE +#define MODSERIAL_DEFAULT_RX_BUFFER_SIZE 256 +#endif + +#ifndef MODSERIAL_DEFAULT_TX_BUFFER_SIZE +#define MODSERIAL_DEFAULT_TX_BUFFER_SIZE 256 +#endif + +#include "mbed.h" +#include "serial_api.h" + +namespace AjK { + +// Forward reference. +class MODSERIAL; + +/** + * @author Andy Kirkham + * @see http://mbed.org/cookbook/MODSERIAL + * @see example3a.cpp + * @see example3b.cpp + * @see API + * + * <b>MODSERIAL_IRQ_INFO</b> is a class used to pass information (and access to protected + * MODSERIAL functions) to IRQ callbacks. + */ +class MODSERIAL_IRQ_INFO +{ +public: + friend class MODSERIAL; + + MODSERIAL *serial; + + MODSERIAL_IRQ_INFO() { serial = 0; } + + /** rxDiscardLastChar() + * + * Remove the last char placed into the rx buffer. + * This is an operation that can only be performed + * by an rxCallback function. + * @ingroup API + * @return The byte removed from the buffer. + */ + int rxDiscardLastChar(void); + +protected: + + /** setSerial() + * + * Used internally by MODSERIAL to set the "this" pointer + * of the MODSERIAL that created this object. + * @ingroup INTERNAL + * @param A pointer to a MODSERIAL object instance. + */ + void setSerial(MODSERIAL *s) { serial = s; } +}; + +// Forward reference dummy class. +class MODSERIAL_callback_dummy; + +/** + * @author Andy Kirkham + * @see http://mbed.org/cookbook/MODSERIAL + * @see example3a.cpp + * @see example3b.cpp + * @see API + * + * <b>MODSERIAL_callback</b> is a class used to hold application callbacks that + * MODSERIAL can invoke on certain events. + */ +class MODSERIAL_callback +{ +protected: + + //! C callback function pointer. + void (*c_callback)(MODSERIAL_IRQ_INFO *); + + //! C++ callback object/method pointer (the object part). + MODSERIAL_callback_dummy *obj_callback; + + //! C++ callback object/method pointer (the method part). + void (MODSERIAL_callback_dummy::*method_callback)(MODSERIAL_IRQ_INFO *); + +public: + + /** Constructor + */ + MODSERIAL_callback() { + c_callback = 0; + obj_callback = 0; + method_callback = 0; + } + + /** attach - Overloaded attachment function. + * + * Attach a C type function pointer as the callback. + * + * Note, the callback function prototype must be:- + * @code + * void myCallbackFunction(MODSERIAL_IRQ_INFO *); + * @endcode + * @param A C function pointer to call. + */ + void attach(void (*function)(MODSERIAL_IRQ_INFO *) = 0) { c_callback = function; } + + /** attach - Overloaded attachment function. + * + * Attach a C++ type object/method pointer as the callback. + * + * Note, the callback method prototype must be:- + * @code + * public: + * void myCallbackFunction(MODSERIAL_IRQ_INFO *); + * @endcode + * @param A C++ object pointer. + * @param A C++ method within the object to call. + */ + template<class T> + void attach(T* item, void (T::*method)(MODSERIAL_IRQ_INFO *)) { + obj_callback = (MODSERIAL_callback_dummy *)item; + method_callback = (void (MODSERIAL_callback_dummy::*)(MODSERIAL_IRQ_INFO *))method; + } + + /** call - Overloaded callback initiator. + * + * call the callback function. + * + * @param A pointer to a MODSERIAL_IRQ_INFO object. + */ + void call(MODSERIAL_IRQ_INFO *arg) { + if (c_callback != 0) { + (*c_callback)(arg); + } + else { + if (obj_callback != 0 && method_callback != 0) { + (obj_callback->*method_callback)(arg); + } + } + } +}; + +/** + * @author Andy Kirkham + * @see http://mbed.org/cookbook/MODSERIAL + * @see http://mbed.org/handbook/Serial + * @see example1.cpp + * @see example2.cpp + * @see example3a.cpp + * @see example3b.cpp + * @see example_dma.cpp + * @see API + * + * <b>MODSERIAL</b> extends the Mbed library <a href="/handbook/Serial">Serial</a> to provide fully buffered + * TX and RX streams. Buffer length is fully customisable. + * + * Before using MODSERIAL users should be familar with Mbed's standard <a href="/handbook/Serial">Serial</a> + * library object. MODSERIAL is a direct "drop in" replacement for <a href="/handbook/Serial">Serial</a>. Where + * previously Serial was used, MODSERIAL can be used as adirect replacement instantly offering standard + * TX and RX buffering. By default, both TX and RX buffers are 256 bytes in length. + * + * @image html /media/uploads/mbedofficial/serial_interfaces.png + * + * Standard example: + * @code + * #include "mbed.h" + * #include "MODSERIAL.h" + * + * MODSERIAL pc(USBTX, USBRX); // tx, rx + * + * int main() { + * pc.printf("Hello World!"); + * while(1) { + * pc.putc(pc.getc() + 1); + * } + * } + * @endcode + * + * Example with alternate buffer length: + * @code + * #include "mbed.h" + * #include "MODSERIAL.h" + * + * // Make TX and RX buffers 512byes in length + * MODSERIAL pc(USBTX, USBRX, 512); // tx, rx + * + * int main() { + * pc.printf("Hello World!"); + * while(1) { + * pc.putc(pc.getc() + 1); + * } + * } + * @endcode + * + * Example with alternate buffer length: + * @code + * #include "mbed.h" + * #include "MODSERIAL.h" + * + * // Make TX 1024bytes and RX 512byes in length + * MODSERIAL pc(USBTX, USBRX, 1024, 512); // tx, rx + * + * int main() { + * pc.printf("Hello World!"); + * while(1) { + * pc.putc(pc.getc() + 1); + * } + * } + * @endcode + */ +class MODSERIAL : public Serial +{ +public: + + // Allow instances of MODSERIAL_IRQ_INFO to use protected properties and methods. + friend class MODSERIAL_IRQ_INFO; + + //! A copy of the Serial parity enum + /** @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.format */ + enum Parity { + None = 0 + , Odd + , Even + , Forced1 + , Forced0 + }; + + //! A copy of the Serial IrqType enum + enum IrqType { + RxIrq = 0 + , TxIrq + , RxOvIrq + , TxOvIrq + , TxEmpty + , RxAutoDetect + , NumOfIrqTypes + }; + + //! Non-blocking functions return code. + enum Result { + Ok = 0 /*!< Ok. */ + , NoMemory = -1 /*!< Memory allocation failed. */ + , NoChar = -1 /*!< No character in buffer. */ + , BufferOversize = -2 /*!< Oversized buffer. */ + }; + + /** + * The MODSERIAL constructor is used to initialise the serial object. + * + * @param tx PinName of the TX pin. + * @param rx PinName of the TX pin. + */ + MODSERIAL(PinName tx, PinName rx, const char* name = NULL); + + /** + * The MODSERIAL constructor is used to initialise the serial object. + * + * @param tx PinName of the TX pin. + * @param rx PinName of the TX pin. + * @param bufferSize Integer of the TX and RX buffer sizes. + */ + MODSERIAL(PinName tx, PinName rx, int bufferSize, const char* name = NULL); + + /** + * The MODSERIAL constructor is used to initialise the serial object. + * + * @param tx PinName of the TX pin. + * @param rx PinName of the TX pin. + * @param txBufferSize Integer of the TX buffer sizes. + * @param rxBufferSize Integer of the RX buffer sizes. + */ + MODSERIAL(PinName tx, PinName rx, int txBufferSize, int rxBufferSize, const char* name = NULL); + + virtual ~MODSERIAL(); + + /** + * Function: attach + * + * The Mbed standard <a href="/handbook/Serial">Serial</a> library object allows an interrupt callback + * to be made when a byte is received by the TX or RX UART hardware. MODSERIAL traps these interrupts + * to enable it's buffering system. However, after the byte has been received/sent under interrupt control, + * MODSERIAL can callback a user function as a notification of the interrupt. Note, user code should not + * directly interact with the Uart hardware, MODSERIAL does that, instead, MODSERIAL API functions should + * be used. + * + * <b>Note</b>, a character is written out then, if there is room in the TX FIFO and the TX buffer is empty, + * putc() will put the character directly into THR (the output holding register). If the TX FIFO is full and + * cannot accept the character, it is placed into the TX output buffer. The TX interrupts are then enabled + * so that when the TX FIFO empties, the TX buffer is then transferred to the THR FIFO. The TxIrq will ONLY + * be activated when this transfer of a character from BUFFER to THR FIFO takes place. If your character + * throughput is not high bandwidth, then the 16 byte TX FIFO may be enough and the TX output buffer may + * never come into play. + * + * @code + * #include "mbed.h" + * #include "MODSERIAL.h" + * + * DigitalOut led1(LED1); + * DigitalOut led2(LED2); + * DigitalOut led3(LED3); + * + * // To test, connect p9 to p10 as a loopback. + * MODSERIAL pc(p9, p10); + * + * // This function is called when a character goes into the TX buffer. + * void txCallback(void) { + * led2 = !led2; + * } + * + * // This function is called when a character goes into the RX buffer. + * void rxCallback(void) { + * led3 = !led3; + * } + * + * int main() { + * pc.baud(115200); + * pc.attach(&txCallback, MODSERIAL::TxIrq); + * pc.attach(&rxCallback, MODSERIAL::RxIrq); + * + * while(1) { + * led1 = !led1; + * wait(0.5); + * pc.putc('A'); + * wait(0.5); + * } + * ] + * @endcode + * + * @ingroup API + * @param fptr A pointer to a void function, or 0 to set as none + * @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty) + */ + void attach(void (*fptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) { _isr[type].attach(fptr); } + + /** + * Function: attach + * + * The Mbed standard <a href="/handbook/Serial">Serial</a> library object allows an interrupt callback + * to be made when a byte is received by the TX or RX UART hardware. MODSERIAL traps these interrupts + * to enable it's buffering system. However, after the byte has been received/sent under interrupt control, + * MODSERIAL can callback a user function as a notification of the interrupt. Note, user code should not + * directly interact with the Uart hardware, MODSERIAL does that, instead, MODSERIAL API functions should + * be used. + * + * <b>Note</b>, a character is written out then, if there is room in the TX FIFO and the TX buffer is empty, + * putc() will put the character directly into THR (the output holding register). If the TX FIFO is full and + * cannot accept the character, it is placed into the TX output buffer. The TX interrupts are then enabled + * so that when the TX FIFO empties, the TX buffer is then transferred to the THR FIFO. The TxIrq will ONLY + * be activated when this transfer of a character from BUFFER to THR FIFO takes place. If your character + * throughput is not high bandwidth, then the 16 byte TX FIFO may be enough and the TX output buffer may + * never come into play. + * + * @code + * #include "mbed.h" + * #include "MODSERIAL.h" + * + * DigitalOut led1(LED1); + * DigitalOut led2(LED2); + * DigitalOut led3(LED3); + * + * // To test, connect p9 to p10 as a loopback. + * MODSERIAL pc(p9, p10); + * + * class Foo { + * public: + * // This method is called when a character goes into the TX buffer. + * void txCallback(void) { led2 = !led2; } + * + * // This method is called when a character goes into the RX buffer. + * void rxCallback(void) { led3 = !led3; } + * }; + * + * Foo foo; + * + * int main() { + * pc.baud(115200); + * pc.attach(&foo, &Foo::txCallback, MODSERIAL::TxIrq); + * pc.attach(&foo, &Foo::rxCallback, MODSERIAL::RxIrq); + * + * while(1) { + * led1 = !led1; + * wait(0.5); + * pc.putc('A'); + * wait(0.5); + * } + * ] + * @endcode + * + * @ingroup API + * @param tptr A pointer to the object to call the member function on + * @param mptr A pointer to the member function to be called + * @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty) + */ + template<typename T> + void attach(T* tptr, void (T::*mptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) { + if((mptr != 0) && (tptr != 0)) { + _isr[type].attach(tptr, mptr); + } + } + + /** + * @see attach + * @ingroup API + */ + void connect(void (*fptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) { _isr[RxIrq].attach(fptr); } + + /** + * @see attach + * @ingroup API + */ + template<typename T> + void connect(T* tptr, void (T::*mptr)(MODSERIAL_IRQ_INFO *), IrqType type = RxIrq) { + if((mptr != 0) && (tptr != 0)) { + _isr[type].attach(tptr, mptr); + } + } + + /** + * Function: writeable + * + * Determine if there is space available to write a byte + * + * @ingroup API + * @return 1 if there is space to write a character, else 0 + */ + int writeable() { return txBufferFull() ? 0 : 1; } + + /** + * Function: readable + * + * Determine if there is a byte available to read + * + * @ingroup API + * @return 1 if there is a character available to read, else 0 + */ + int readable() { return rxBufferEmpty() ? 0 : 1; } + + /** + * Function: txBufferSane + * + * Determine if the TX buffer has been initialized. + * + * @ingroup API + * @return true if the buffer is initialized, else false + */ + bool txBufferSane(void) { return buffer[TxIrq] != (char *)NULL ? true : false; } + + /** + * Function: rxBufferSane + * + * Determine if the RX buffer has been initialized. + * + * @ingroup API + * @return true if the buffer is initialized, else false + */ + bool rxBufferSane(void) { return buffer[TxIrq] != (char *)NULL ? true : false; } + + /** + * Function: txBufferGetCount + * + * Returns how many bytes are in the TX buffer + * + * @ingroup API + * @return The number of bytes in the TX buffer + */ + int txBufferGetCount(void) { return buffer_count[TxIrq]; } + + /** + * Function: rxBufferGetCount + * + * Returns how many bytes are in the RX buffer + * + * @ingroup API + * @return The number of bytes in the RX buffer + */ + int rxBufferGetCount(void) { return buffer_count[RxIrq]; } + + /** + * Function: txBufferGetSize + * + * Returns the current size of the TX buffer + * + * @ingroup API + * @return The length iof the TX buffer in bytes + */ + int txBufferGetSize(int size) { return buffer_size[TxIrq]; } + + /** + * Function: rxBufferGetSize + * + * Returns the current size of the RX buffer + * + * @ingroup API + * @return The length iof the RX buffer in bytes + */ + int rxBufferGetSize(int size) { return buffer_size[RxIrq]; } + + /** + * Function: txBufferFull + * + * Is the TX buffer full? + * + * @ingroup API + * @return true if the TX buffer is full, otherwise false + */ + bool txBufferFull(void); + + /** + * Function: rxBufferFull + * + * Is the RX buffer full? + * + * @ingroup API + * @return true if the RX buffer is full, otherwise false + */ + bool rxBufferFull(void); + + /** + * Function: txBufferEmpty + * + * Is the TX buffer empty? + * + * @ingroup API + * @return true if the TX buffer is empty, otherwise false + */ + bool txBufferEmpty(void); + + /** + * Function: rxBufferEmpty + * + * Is the RX buffer empty? + * + * @ingroup API + * @return true if the RX buffer is empty, otherwise false + */ + bool rxBufferEmpty(void); + + /** + * Function: txBufferSetSize + * + * Change the TX buffer size. + * + * @see Result + * @ingroup API + * @param size The new TX buffer size in bytes. + * @param m Perform a memory sanity check. Errs the Mbed if memory alloc fails. + * @return Result Ok on success. + */ + int txBufferSetSize(int size, bool m) { return resizeBuffer(size, TxIrq, m); } + + /** + * Function: rxBufferSetSize + * + * Change the RX buffer size. + * + * @see Result + * @ingroup API + * @param size The new RX buffer size in bytes. + * @param m Perform a memory sanity check. Errs the Mbed if memory alloc fails. + * @return Result Ok on success. + */ + int rxBufferSetSize(int size, bool m) { return resizeBuffer(size, RxIrq, m); } + + /** + * Function: txBufferSetSize + * + * Change the TX buffer size. + * Always performs a memory sanity check, halting the Mbed on failure. + * + * @see Result + * @ingroup API + * @param size The new TX buffer size in bytes. + * @return Result Ok on success. + */ + int txBufferSetSize(int size) { return resizeBuffer(size, TxIrq, true); } + + /** + * Function: rxBufferSetSize + * + * Change the RX buffer size. + * Always performs a memory sanity check, halting the Mbed on failure. + * + * @see Result + * @ingroup API + * @param size The new RX buffer size in bytes. + * @return Result Ok on success. + */ + int rxBufferSetSize(int size) { return resizeBuffer(size, RxIrq, true); } + + /** + * Function: txBufferFlush + * + * Remove all bytes from the TX buffer. + * @ingroup API + */ + void txBufferFlush(void) { flushBuffer(TxIrq); } + + /** + * Function: rxBufferFlush + * + * Remove all bytes from the RX buffer. + * @ingroup API + */ + void rxBufferFlush(void) { flushBuffer(RxIrq); } + + /** + * Function: getcNb + * + * Like getc() but is non-blocking. If no bytes are in the RX buffer this + * function returns Result::NoChar (-1) + * + * @ingroup API + * @return A byte from the RX buffer or Result::NoChar (-1) if bufer empty. + */ + int getcNb() { return __getc(false); } + + /** + * Function: getc + * + * Overloaded version of Serial::getc() + * + * This function blocks (if the RX buffer is empty the function will wait for a + * character to arrive and then return that character). + * + * @ingroup API + * @return A byte from the RX buffer + */ + int getc() { return __getc(true); } + + /** + * Function: txGetLastChar + * + * Rteurn the last byte to pass through the TX interrupt handler. + * + * @ingroup MISC + * @return The byte + */ + char txGetLastChar(void) { return txc; } + + /** + * Function: rxGetLastChar + * + * Return the last byte to pass through the RX interrupt handler. + * + * @ingroup MISC + * @return The byte + */ + char rxGetLastChar(void) { return rxc; } + + /** + * Function: txIsBusy + * + * If the Uart is still actively sending characters this + * function will return true. + * + * @ingroup API + * @return bool + */ + bool txIsBusy(void); + + /** + * Function: autoDetectChar + * + * Set the char that, if seen incoming, invokes the AutoDetectChar callback. + * + * @ingroup API + * @param int c The character to detect. + */ + void autoDetectChar(char c) { auto_detect_char = c; } + + /** + * Function: move + * + * Move contents of RX buffer to external buffer. Stops if "end" detected. + * + * @ingroup API + * @param char *s The destination buffer address + * @param int max The maximum number of chars to move. + * @param char end If this char is detected stop moving. + */ + int move(char *s, int max, char end) { + int counter = 0; + char c; + while(readable()) { + c = getc(); + if (c == end) break; + *(s++) = c; + counter++; + if (counter == max) break; + } + return counter; + } + + /** + * Function: move (overloaded) + * + * Move contents of RX buffer to external buffer. Stops if auto_detect_char detected. + * + * @ingroup API + * @param int max The maximum number of chars to move. + * @param char *s The destination buffer address + */ + int move(char *s, int max) { + return move(s, max, auto_detect_char); + } + + #if 0 // Inhereted from Serial/Stream, for documentation only + /** + * Function: putc + * + * Write a character + * Inhereted from Serial/Stream + * + * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.putc + * @ingroup API + * @param c The character to write to the serial port + */ + int putc(int c); + #endif + + #if 0 // Inhereted from Serial/Stream, for documentation only + /** + * Function: printf + * + * Write a formated string + * Inhereted from Serial/Stream + * + * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.printf + * @ingroup API + * @param format A printf-style format string, followed by the variables to use in formating the string. + */ + int printf(const char* format, ...); + #endif + + #if 0 // Inhereted from Serial/Stream, for documentation only + /** + * Function: scanf + * + * Read a formated string + * Inhereted from Serial/Stream + * + * @see http://mbed.org/projects/libraries/api/mbed/trunk/Serial#Serial.scanf + * @ingroup API + * @param format - A scanf-style format string, followed by the pointers to variables to store the results. + */ + int scanf(const char* format, ...); + #endif + +protected: + /** + * Used to pass information to callbacks. + * @ingroup INTERNALS + */ + MODSERIAL_IRQ_INFO callbackInfo; + + /** + * Remove the last char placed into the rx buffer. + * This is an operation that can only be performed + * by an rxCallback function. To protect the buffers + * this function is defined protected so that a + * regular application cannot call it directly. It + * can only be called by the public version within a + * MODSERIAL_IRQ_INFO class. + * @ingroup INTERNALS + * @return The byte removed from the buffer. + */ + int rxDiscardLastChar(void); + +private: + + /** + * A pointer to the UART peripheral base address being used. + * @ingroup INTERNALS + */ + void *_base; + + /** + * The last byte to pass through the TX IRQ handler. + * @ingroup INTERNALS + */ + volatile char txc; + + /** + * The last byte to pass through the RX IRQ handler. + * @ingroup INTERNALS + */ + volatile char rxc; + + /** + * Pointers to the TX and RX buffers. + * @ingroup INTERNALS + */ + volatile char *buffer[2]; + + /** + * Buffer in pointers. + * @ingroup INTERNALS + */ + volatile int buffer_in[2]; + + /** + * Buffer out pointers. + * @ingroup INTERNALS + */ + volatile int buffer_out[2]; + + /** + * Buffer lengths. + * @ingroup INTERNALS + */ + volatile int buffer_size[2]; + + /** + * Buffer content counters. + * @ingroup INTERNALS + */ + volatile int buffer_count[2]; + + /** + * Buffer overflow. + * @ingroup INTERNALS + */ + volatile int buffer_overflow[2]; + + /** + * Auto-detect character. + * @ingroup INTERNALS + */ + volatile char auto_detect_char; + + /** + * Callback system. + * @ingroup INTERNALS + */ + MODSERIAL_callback _isr[NumOfIrqTypes]; + + /** + * TX Interrupt Service Routine. + * @ingroup INTERNALS + */ + void isr_tx(bool doCallback); + + /** + * TX Interrupt Service Routine stub version. + * @ingroup INTERNALS + */ + void isr_tx(void) { isr_tx(true); } + + + /** + * RX Interrupt Service Routine. + * @ingroup INTERNALS + */ + void isr_rx(void); + + /** + * Disable the interrupts for this Uart. + * @ingroup INTERNALS + */ + void disableIrq(void); + + /** + * Enable the interrupts for this Uart. + * @ingroup INTERNALS + */ + void enableIrq(void); + + /** + * Get a character from the RX buffer + * @ingroup INTERNALS + * @param bool True to block (wait for input) + * @return A byte from the buffer. + */ + int __getc(bool); + + /** + * Put a character from the TX buffer + * @ingroup INTERNALS + * @param bool True to block (wait for space in the TX buffer if full) + * @return 0 on success + */ + int __putc(int c, bool); + + /** + * Function: _putc + * Overloaded virtual function. + */ + virtual int _putc(int c) { return __putc(c, true); } + + /** + * Function: _getc + * Overloaded virtual function. + */ + virtual int _getc() { return __getc(true); } + + /** + * Function: init + * Initialize the MODSERIAL object + * @ingroup INTERNALS + */ + void init(int txSize, int rxSize, PinName rx); + + /** + * Function: flushBuffer + * @ingroup INTERNALS + */ + void flushBuffer(IrqType type); + + /** + * Function: resizeBuffer + * @ingroup INTERNALS + */ + int resizeBuffer(int size, IrqType type = RxIrq, bool memory_check = true); + + /** + * Function: downSizeBuffer + * @ingroup INTERNALS + */ + int downSizeBuffer(int size, IrqType type, bool memory_check); + + /** + * Function: upSizeBuffer + * @ingroup INTERNALS + */ + int upSizeBuffer(int size, IrqType type, bool memory_check); + + /* + * If MODDMA is available the compile in code to handle sending + * an arbitary char buffer. Note, the parts before teh #ifdef + * are declared so that MODSERIAL can access then even if MODDMA + * isn't avaiable. Since MODDMA.h is only available at this point + * all DMA functionality must be declared inline in the class + * definition. + */ +public: + + int dmaSendChannel; + void *moddma_p; + +#ifdef MODDMA_H + + MODDMA_Config *config; + + /** + * Set the "void pointer" moddma_p to be a pointer to a + * MODDMA controller class instance. Used to manage the + * data transfer of DMA configurations. + * + * @ingroup API + * @param p A pointer to "the" instance of MODDMA. + */ + void MODDMA(MODDMA *p) { moddma_p = p; } + + /** + * Send a char buffer to the Uarts TX system + * using DMA. This blocks regular library + * sending. + * + * @param buffer A char buffer of bytes to send. + * @param len The length of the buffer to send. + * @param dmaChannel The DMA channel to use, defaults to 7 + * @return MODDMA::Status MODDMA::ok if all went ok + */ + int dmaSend(char *buffer, int len, int dmaChannel = 7) + { + if (moddma_p == (void *)NULL) return -2; + class MODDMA *dma = (class MODDMA *)moddma_p; + + dmaSendChannel = dmaChannel & 0x7; + + uint32_t conn = MODDMA::UART0_Tx; + switch(_serial.index) { + case 0: conn = MODDMA::UART0_Tx; break; + case 1: conn = MODDMA::UART1_Tx; break; + case 2: conn = MODDMA::UART2_Tx; break; + case 3: conn = MODDMA::UART3_Tx; break; + } + + config = new MODDMA_Config; + config + ->channelNum ( (MODDMA::CHANNELS)(dmaSendChannel & 0x7) ) + ->srcMemAddr ( (uint32_t) buffer ) + ->transferSize ( len ) + ->transferType ( MODDMA::m2p ) + ->dstConn ( conn ) + ->attach_tc ( this, &MODSERIAL::dmaSendCallback ) + ->attach_err ( this, &MODSERIAL::dmaSendCallback ) + ; // config end + + // Setup the configuration. + if (dma->Setup(config) == 0) { + return -1; + } + + //dma.Enable( MODDMA::Channel_0 ); + dma->Enable( config->channelNum() ); + return MODDMA::Ok; + } + + /** + * Attach a callback to the DMA completion. + * + * @ingroup API + * @param fptr A function pointer to call + * @return this + */ + void attach_dmaSendComplete(void (*fptr)(MODSERIAL_IRQ_INFO *)) { + _isrDmaSendComplete.attach(fptr); + } + + /** + * Attach a callback to the DMA completion. + * + * @ingroup API + * @param tptr A template pointer to the calling object + * @param mptr A method pointer within the object to call. + * @return this + */ + template<typename T> + void attach_dmaSendComplete(T* tptr, void (T::*mptr)(MODSERIAL_IRQ_INFO *)) { + if((mptr != NULL) && (tptr != NULL)) { + _isrDmaSendComplete.attach(tptr, mptr); + } + } + + MODSERIAL_callback _isrDmaSendComplete; + +protected: + /** + * Callback for dmaSend(). + */ + void dmaSendCallback(void) + { + if (moddma_p == (void *)NULL) return; + class MODDMA *dma = (class MODDMA *)moddma_p; + + MODDMA_Config *config = dma->getConfig(); + dma->haltAndWaitChannelComplete( (MODDMA::CHANNELS)config->channelNum()); + dma->Disable( (MODDMA::CHANNELS)config->channelNum() ); + if (dma->irqType() == MODDMA::TcIrq) dma->clearTcIrq(); + if (dma->irqType() == MODDMA::ErrIrq) dma->clearErrIrq(); + dmaSendChannel = -1; + _isrDmaSendComplete.call(&this->callbackInfo); + delete(config); + } + +#endif // MODDMA_H + +}; + +}; // namespace AjK ends + +using namespace AjK; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODSERIAL/MODSERIAL_IRQ_INFO.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,38 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + @file MODSERIAL_IRQ_INFO.cpp + @author Andy Kirkham +*/ + +#include "MODSERIAL.h" + +namespace AjK { + +int +MODSERIAL_IRQ_INFO::rxDiscardLastChar(void) +{ + if (!serial) return -1; + + return serial->rxDiscardLastChar(); +} + +}; // namespace AjK ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODSERIAL/PUTC.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,81 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +int +MODSERIAL::__putc(int c, bool block) { + + // If no buffer is in use fall back to standard TX FIFO usage. + // Note, we must block in this case and ignore bool "block" + // so as to maintain compat with Mbed Serial. + if (buffer[TxIrq] == (char *)NULL || buffer_size[TxIrq] == 0) { + while (! MODSERIAL_THR_HAS_SPACE) ; // Wait for space in the TX FIFO. + _THR = (uint32_t)c; + return 0; + } + + if ( MODSERIAL_THR_HAS_SPACE && MODSERIAL_TX_BUFFER_EMPTY && dmaSendChannel == -1 ) { + _THR = (uint32_t)c; + } + else { + if (block) { + uint32_t ier = _IER; _IER = 1; + while ( MODSERIAL_TX_BUFFER_FULL ) { // Blocks! + // If putc() is called from an ISR then we are stuffed + // because in an ISR no bytes from the TX buffer will + // get transferred to teh TX FIFOs while we block here. + // So, to work around this, instead of sitting in a + // loop waiting for space in the TX buffer (which will + // never happen in IRQ context), check to see if the + // TX FIFO has space available to move bytes from the + // TX buffer to TX FIFO to make space. The easiest way + // to do this is to poll the isr_tx() function while we + // are blocking. + isr_tx(false); + } + _IER = ier; + } + else if( MODSERIAL_TX_BUFFER_FULL ) { + buffer_overflow[TxIrq] = c; // Oh dear, no room in buffer. + _isr[TxOvIrq].call(&this->callbackInfo); + return -1; + } + _IER &= ~2; + buffer[TxIrq][buffer_in[TxIrq]] = c; + __disable_irq(); + buffer_count[TxIrq]++; + __enable_irq(); + buffer_in[TxIrq]++; + if (buffer_in[TxIrq] >= buffer_size[TxIrq]) { + buffer_in[TxIrq] = 0; + } + _IER |= 2; + } + + return 0; +} + +}; // namespace AjK ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODSERIAL/RESIZE.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,123 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MODSERIAL.h" +#include "MACROS.h" + +namespace AjK { + +int +MODSERIAL::resizeBuffer(int size, IrqType type, bool memory_check) +{ + int rval = Ok; + + // If the requested size is the same as the current size there's nothing to do, + // just continue to use the same buffer as it's fine as it is. + if (buffer_size[type] == size) return rval; + + // Make sure the ISR cannot use the buffers while we are manipulating them. + disableIrq(); + + // If the requested buffer size is larger than the current size, + // attempt to create a new buffer and use it. + if (buffer_size[type] < size) { + rval = upSizeBuffer(size, type, memory_check); + } + else if (buffer_size[type] > size) { + rval = downSizeBuffer(size, type, memory_check); + } + + // Start the ISR system again with the new buffers. + enableIrq(); + + return rval; +} + +int +MODSERIAL::downSizeBuffer(int size, IrqType type, bool memory_check) +{ + if (size >= buffer_count[type]) { + return BufferOversize; + } + + char *s = (char *)malloc(size); + + if (s == (char *)NULL) { + if (memory_check) { + error("Failed to allocate memory for %s buffer", type == TxIrq ? "TX" : "RX"); + } + return NoMemory; + } + + int c, new_in = 0; + + do { + c = __getc(false); + if (c != -1) s[new_in++] = (char)c; + if (new_in >= size) new_in = 0; + } + while (c != -1); + + free((char *)buffer[type]); + buffer[type] = s; + buffer_in[type] = new_in; + buffer_out[type] = 0; + return Ok; +} + +int +MODSERIAL::upSizeBuffer(int size, IrqType type, bool memory_check) +{ + char *s = (char *)malloc(size); + + if (s == (char *)NULL) { + if (memory_check) { + error("Failed to allocate memory for %s buffer", type == TxIrq ? "TX" : "RX"); + } + return NoMemory; + } + + if (buffer_count[type] == 0) { // Current buffer empty? + free((char *)buffer[type]); + buffer[type] = s; + buffer_in[type] = 0; + buffer_out[type] = 0; + } + else { // Copy the current contents into the new buffer. + int c, new_in = 0; + do { + c = __getc(false); + if (c != -1) s[new_in++] = (char)c; + if (new_in >= size) new_in = 0; // Shouldn't happen, but be sure. + } + while (c != -1); + free((char *)buffer[type]); + buffer[type] = s; + buffer_in[type] = new_in; + buffer_out[type] = 0; + } + + buffer_size[type] = size; + return Ok; +} + +}; // namespace AjK ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODSERIAL/example1.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,120 @@ +#ifdef COMPILE_EXAMPLE1_CODE_MODSERIAL + +/* + * To run this test program, link p9 to p10 so the Serial loops + * back and receives characters it sends. + */ + +#include "mbed.h" +#include "MODSERIAL.h" + +DigitalOut led1(LED1); +DigitalOut led2(LED2); +DigitalOut led3(LED3); +DigitalOut led4(LED4); + +MODSERIAL pc(USBTX, USBRX); + +/* + * As experiement, you can define MODSERIAL as show here and see what + * effects it has on the LEDs. + * + * MODSERIAL uart(TX_PIN, RX_PIN, 512); + * With this, the 512 characters sent can straight into the buffer + * vary quickly. This means LED1 is only on briefly as the TX buffer + * fills. + * + * MODSERIAL uart(TX_PIN, RX_PIN, 32); + * With this, the buffer is smaller than the default 256 bytes and + * therefore LED1 stays on much longer while the system waits for + * room in the TX buffer. + */ +MODSERIAL uart(TX_PIN, RX_PIN); + +// This function is called when a character goes from the TX buffer +// to the Uart THR FIFO register. +void txCallback(MODSERIAL_IRQ_INFO *q) { + led2 = !led2; +} + +// This function is called when TX buffer goes empty +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(MODSERIAL_IRQ_INFO *q) { + led3 = !led3; + pc.putc(uart.getc()); +} + +int main() { + int c = 'A'; + + // Ensure the baud rate for the PC "USB" serial is much + // higher than "uart" baud rate below. + pc.baud(PC_BAUD); + + // Use a deliberatly slow baud to fill up the TX buffer + uart.baud(1200); + + uart.attach(&txCallback, MODSERIAL::TxIrq); + uart.attach(&rxCallback, MODSERIAL::RxIrq); + uart.attach(&txEmpty, MODSERIAL::TxEmpty); + + // Loop sending characters. We send 512 + // which is twice the default TX/RX buffer size. + + led1 = 1; // Show start of sending with LED1. + + for (int loop = 0; loop < 512; loop++) { + uart.printf("%c", c); + c++; + if (c > 'Z') c = 'A'; + } + + led1 = 0; // Show the end of sending by switching off LED1. + + // End program. Flash LED4. Notice how LED 2 and 3 continue + // to flash for a short period while the interrupt system + // continues to send the characters left in the TX buffer. + + while(1) { + led4 = !led4; + wait(0.25); + } +} + +/* + * Notes. Here is the sort of output you can expect on your PC/Mac/Linux host + * machine that is connected to the "pc" USB serial port. + * + * ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUV + * WXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR + * STUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN + * OPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJ + * KLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF + * GHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZAB + * CDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ Done. R + * + * Of interest is that last "R" character after the system has said "Done." + * This comes from the fact that the TxEmpty callback is made when the TX buffer + * becomes empty. MODSERIAL makes use of the fact that the Uarts built into the + * LPC17xx device use a 16 byte FIFO on both RX and TX channels. This means that + * when the TxEmpty callback is made, the TX buffer is empty, but that just means + * the "last few characters" were written to the TX FIFO. So although the TX + * buffer has gone empty, the Uart's transmit system is still sending any remaining + * characters from it's TX FIFO. If you want to be truely sure all the characters + * you have sent have left the Mbed then call txIsBusy(); This function will + * return true if characters are still being sent. If it returns false after + * the Tx buffer is empty then all your characters have been sent. + * + * In a similar way, when characters are received into the RX FIFO, the entire + * FIFO contents is moved to the RX buffer, assuming there is room left in the + * RX buffer. If there is not, any remaining characters are left in the RX FIFO + * and will be moved to the RX buffer on the next interrupt or when the running + * program removes a character(s) from the RX buffer with the getc() method. + */ + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODSERIAL/example2.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,167 @@ +/* + 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 example2.cpp + @purpose Demos a simple messaging system. + @version see ChangeLog.c + @date Jan 2011 + @author Andy Kirkham +*/ + +/* + This example demostrates a simple "messaging" system. You can use it with + a terminal program to test it out or write a cusom C#/C++/VB/etc program + to read and write messages to or from the Mbed. The default baud rate in + this example is 115200. + + In this example, the LEDs are controlled and pins p21 to p24 are set as + InterruptIn and send messages out when their value changes. + + To use, hook up the MBed USB and open your fav terminal. All messages + end with the \n character, don't forget to hit carriage return!. + As an example:- + + to switch on LED1 send LED1:1\n, off is LED1:0\n and toggle is LED1:2\n + to switch on LED2 send LED2:1\n, off is LED2:0\n and toggle is LED2:2\n + to switch on LED3 send LED3:1\n, off is LED3:0\n and toggle is LED3:2\n + to switch on LED4 send LED4:1\n, off is LED4:0\n and toggle is LED4:2\n + + When a pin change on p21 to p24 happens, a message is sent. As an example + when p21 goes low PIN21:0\n is sent, when goes high PIN21:1\n is sent. + + Note, the InterruptIn pins p21 to p24 are setup to have pullups. This means + they are high. To activate them use a wire to short the pin to 0volts. + + If you find that p21 to p24 sent a lot of on/off/on/off then it's probably + due to "bounce". If you are connecting a mechanical switch to a pin you + may prefer to use the PinDetect library rather than using InterruptIn. + @see http://mbed.org/users/AjK/libraries/PinDetect/latest + + One point you may notice. Incoming messages are processed via main()'s + while(1) loop whereas pin changes have their messages directly sent. + The reason for this is when MODSERIAL makes callbacks to your application + it is in "interrupt context". And one thing you want to avoid is spending + lots of CPU time in that context. So, the callback moves the message from + the input buffer to a local holding buffer and it then sets a bool flag + which tells main()'s while(1) loop to process that buffer. This means the + time spent doing the real incoming message handing is within your program + and not within MODSERIAL's interrupt context. So you may ask, why not do + the same for out going messages? Well, because MODSERIAL output buffers + all your sent content then sending chars is very fast. MODSERIAL handles + all the nitty gritty bits for you. You can just send. This example uses + puts() to send the message. If you can, always try and use sprintf()+puts() + rathe than printf(), printf() is known to often screw things up when used + within an interrupt context. Better still, just use puts() and do away + with any of the crappy ?printf() calls if possible. But I found the code + below to work fine even at 115200baud. + +*/ + + +#ifdef COMPILE_EXAMPLE1_CODE_MODSERIAL + +#include "mbed.h" +#include "MODSERIAL.h" + +#define MESSAGE_BUFFER_SIZE 32 + +DigitalOut led1(LED1); +DigitalOut led2(LED2); +DigitalOut led3(LED3); +DigitalOut led4(LED4); + +InterruptIn P21(p21); +InterruptIn P22(p22); +InterruptIn P23(p23); +InterruptIn P24(p24); + +MODSERIAL messageSystem(USBTX, USBRX); + +char messageBufferIncoming[MESSAGE_BUFFER_SIZE]; +char messageBufferOutgoing[MESSAGE_BUFFER_SIZE]; +bool messageReceived; + +void messageReceive(MODSERIAL_IRQ_INFO *q) { + MODSERIAL *sys = q->serial; + sys->move(messageBufferIncoming, MESSAGE_BUFFER_SIZE); + messageReceived = true; + return 0; +} + +void messageProcess(void) { + if (!strncmp(messageBufferIncoming, "LED1:1", sizeof("LED1:1")-1)) led1 = 1; + else if (!strncmp(messageBufferIncoming, "LED1:0", sizeof("LED1:0")-1)) led1 = 0; + else if (!strncmp(messageBufferIncoming, "LED1:2", sizeof("LED1:2")-1)) led1 = !led1; + + else if (!strncmp(messageBufferIncoming, "LED2:1", sizeof("LED2:1")-1)) led2 = 1; + else if (!strncmp(messageBufferIncoming, "LED2:0", sizeof("LED2:0")-1)) led2 = 0; + else if (!strncmp(messageBufferIncoming, "LED2:2", sizeof("LED2:2")-1)) led2 = !led2; + + else if (!strncmp(messageBufferIncoming, "LED3:1", sizeof("LED3:1")-1)) led3 = 1; + else if (!strncmp(messageBufferIncoming, "LED3:0", sizeof("LED3:0")-1)) led3 = 0; + else if (!strncmp(messageBufferIncoming, "LED3:2", sizeof("LED3:2")-1)) led3 = !led3; + + else if (!strncmp(messageBufferIncoming, "LED4:1", sizeof("LED4:1")-1)) led4 = 1; + else if (!strncmp(messageBufferIncoming, "LED4:0", sizeof("LED4:0")-1)) led4 = 0; + else if (!strncmp(messageBufferIncoming, "LED4:2", sizeof("LED4:2")-1)) led4 = !led4; + + messageReceived = false; +} + +#define PIN_MESSAGE_SEND(x,y) \ + sprintf(messageBufferOutgoing,"PIN%02d:%d\n",x,y);\ + messageSystem.puts(messageBufferOutgoing); + +void pin21Rise(void) { PIN_MESSAGE_SEND(21, 1); } +void pin21Fall(void) { PIN_MESSAGE_SEND(21, 0); } +void pin22Rise(void) { PIN_MESSAGE_SEND(22, 1); } +void pin22Fall(void) { PIN_MESSAGE_SEND(22, 0); } +void pin23Rise(void) { PIN_MESSAGE_SEND(23, 1); } +void pin23Fall(void) { PIN_MESSAGE_SEND(23, 0); } +void pin24Rise(void) { PIN_MESSAGE_SEND(24, 1); } +void pin24Fall(void) { PIN_MESSAGE_SEND(24, 0); } + +int main() { + + messageReceived = false; + messageSystem.baud(115200); + messageSystem.attach(&messageReceive, MODSERIAL::RxAutoDetect); + messageSystem.autoDetectChar('\n'); + + // Enable pullup resistors on pins. + P21.mode(PullUp); P22.mode(PullUp); P23.mode(PullUp); P24.mode(PullUp); + + // Fix Mbed library bug, see http://mbed.org/forum/bugs-suggestions/topic/1498 + LPC_GPIOINT->IO2IntClr = (1UL << 5) | (1UL << 4) | (1UL << 3) | (1UL << 2); + + // Attach InterruptIn pin callbacks. + P21.rise(&pin21Rise); P21.fall(&pin21Fall); + P22.rise(&pin22Rise); P22.fall(&pin22Fall); + P23.rise(&pin23Rise); P23.fall(&pin23Fall); + P24.rise(&pin24Rise); P24.fall(&pin24Fall); + + while(1) { + // Process incoming messages. + if (messageReceived) messageProcess(); + } +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODSERIAL/example3a.cpp Fri Nov 14 06:05:59 2014 +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/Libs/MODSERIAL/example3b.cpp Fri Nov 14 06:05:59 2014 +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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/MODSERIAL/example_dma.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,144 @@ +#ifdef COMPILE_EXAMPLE_CODE_MODSERIAL_MODDMA + +/* + * To run this test program, link p9 to p10 so the Serial loops + * back and receives characters it sends. + */ + +#include "mbed.h" + +/* Note, this example requires that you also import into the Mbed + compiler the MODDMA project as well as MODSERIAL + http://mbed.org/users/AjK/libraries/MODDMA/latest + MODDMA.h MUST come before MODSERIAL.h */ +#include "MODDMA.h" // <--- Declare first +#include "MODSERIAL.h" // Flollowed by MODSERIAL + +DigitalOut led1(LED1); +DigitalOut led2(LED2); +DigitalOut led3(LED3); +DigitalOut led4(LED4); + +MODSERIAL pc(USBTX, USBRX); + +/* + * As experiement, you can define MODSERIAL as show here and see what + * effects it has on the LEDs. + * + * MODSERIAL uart(TX_PIN, RX_PIN, 512); + * With this, the 512 characters sent can straight into the buffer + * vary quickly. This means LED1 is only on briefly as the TX buffer + * fills. + * + * MODSERIAL uart(TX_PIN, RX_PIN, 32); + * With this, the buffer is smaller than the default 256 bytes and + * therefore LED1 stays on much longer while the system waits for + * room in the TX buffer. + */ +MODSERIAL uart(TX_PIN, RX_PIN); + +MODDMA dma; + +// This function is called when a character goes from the TX buffer +// to the Uart THR FIFO register. +void txCallback(void) { + led2 = !led2; +} + +// This function is called when TX buffer goes empty +void txEmpty(void) { + led2 = 0; + pc.puts(" Done. "); +} + +void dmaComplete(void) { + led1 = 1; +} + +// This function is called when a character goes into the RX buffer. +void rxCallback(void) { + led3 = !led3; + pc.putc(uart.getc()); +} + +int main() { + char s1[] = " *DMA* *DMA* *DMA* *DMA* *DMA* *DMA* *DMA* "; + int c = 'A'; + + // Tell MODSERIAL where the MODDMA controller is. + pc.MODDMA( &dma ); + + // Ensure the baud rate for the PC "USB" serial is much + // higher than "uart" baud rate below. + pc.baud( PC_BAUD ); + + // Use a deliberatly slow baud to fill up the TX buffer + uart.baud(1200); + + uart.attach( &txCallback, MODSERIAL::TxIrq ); + uart.attach( &rxCallback, MODSERIAL::RxIrq ); + uart.attach( &txEmpty, MODSERIAL::TxEmpty ); + + // Loop sending characters. We send 512 + // which is twice the default TX/RX buffer size. + + led1 = 0; + + // Send the buffer s using DMA channel 7 + pc.attach_dmaSendComplete( &dmaComplete ); + pc.dmaSend( s1, sizeof(s1), MODDMA::Channel_7 ); + + for (int loop = 0; loop < 512; loop++) { + uart.printf("%c", c); + c++; + if (c > 'Z') c = 'A'; + } + + led1 = 0; // Show the end of sending by switching off LED1. + + // End program. Flash LED4. Notice how LED 2 and 3 continue + // to flash for a short period while the interrupt system + // continues to send the characters left in the TX buffer. + + while(1) { + led4 = !led4; + wait(0.25); + } +} + +/* + * Notes. Here is the sort of output you can expect on your PC/Mac/Linux host + * machine that is connected to the "pc" USB serial port. + * + * *DMA* *DMA* *DMA* *DMA* *DMA* *DMA* *DMA* ABCDEFGHIJKLMNOPQRSTUVWXYZABCDE + * FGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZA + * BCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVW + * XYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRS + * TUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNO + * PQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJK + * LMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFG + * HIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ Done. R + * + * Note how the DMA blocks the TX buffer sending under standard interrupt control. + * Not until the DMA transfer is complete will "normal" buffered TX sending resume. + * + * Of interest is that last "R" character after the system has said "Done." + * This comes from the fact that the TxEmpty callback is made when the TX buffer + * becomes empty. MODSERIAL makes use of the fact that the Uarts built into the + * LPC17xx device use a 16 byte FIFO on both RX and TX channels. This means that + * when the TxEmpty callback is made, the TX buffer is empty, but that just means + * the "last few characters" were written to the TX FIFO. So although the TX + * buffer has gone empty, the Uart's transmit system is still sending any remaining + * characters from it's TX FIFO. If you want to be truely sure all the characters + * you have sent have left the Mbed then call txIsBusy(); This function will + * return true if characters are still being sent. If it returns false after + * the Tx buffer is empty then all your characters have been sent. + * + * In a similar way, when characters are received into the RX FIFO, the entire + * FIFO contents is moved to the RX buffer, assuming there is room left in the + * RX buffer. If there is not, any remaining characters are left in the RX FIFO + * and will be moved to the RX buffer on the next interrupt or when the running + * program removes a character(s) from the RX buffer with the getc() method. + */ + +#endif
--- a/Libs/Xbee/Xbee.cpp Thu Nov 13 10:53:10 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -#include "Xbee.h" - -Xbee::Xbee(PinName tx, PinName rx, int baudrate, int bufferSize, char _delim) : xbee(tx, rx, bufferSize) { - xbee.baud(baudrate); - charCounter = 0; - numMessagesIn = 0; - numMessagesOut = 0; - delim = _delim; - - // Attach callback when a new message delimiter character arrives - xbee.autoDetectChar(delim); - xbee.attach(this, &Xbee::newMsg, MODSERIAL::RxAutoDetect); -} -bool Xbee::send(CANMessage& msg) { - if (!xbee.writeable()) return false; // Exit, txBuffer full - - // Format as string - char str[100]; - - // Will it fit? - if (xbee.txBufferGetSize(0) - xbee.txBufferGetCount() > strlen(str)){ - xbee.printf("%s\n", str); - numMessagesOut++; - return true; - - // Don't send - } else { - return false; - } -} -bool Xbee::receive(CANMessage& msg) { - char str[100]; - unsigned int i = 0; - - if (charCounter == 0) return false; // No messages yet - else { - while (xbee.readable()) { // Build string until buffer is empty or delimiter char is found - char c = xbee.getc(); - str[i] = c; - i++; - if (c == delim) { - charCounter--; - str[i-1] = '\0'; // Null terminator in place of delimiter char - break; - } - } - } - - // Process string into CAN Message - int len = strlen(str); - - numMessagesIn++; - return true; -} -void Xbee::newMsg(MODSERIAL_IRQ_INFO *q) { - charCounter++; -} \ No newline at end of file
--- a/Libs/Xbee/Xbee.h Thu Nov 13 10:53:10 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -#ifndef __XBEE_FILE_H -#define __XBEE_FILE_H - -#include "mbed.h" -#include "MODSERIAL.h" - -class Xbee { -public: - Xbee(PinName tx, PinName rx, int baudrate, int bufferSize, char delim='\n'); - bool send(CANMessage& msg); - bool receive(CANMessage& msg); - unsigned int messagesProcessedOut() { return numMessagesOut; } - unsigned int messagesProcessedIn() { return numMessagesIn; } -private: - MODSERIAL xbee; - volatile unsigned int numMessagesIn; - volatile unsigned int numMessagesOut; - - // Interrupt function called on receipt of message delimitter char - void newMsg(MODSERIAL_IRQ_INFO *q); - char delim; // Delimitter char that ends each message - volatile unsigned int charCounter; // Number of messages received so far in the serial buffer -}; - -#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/xbeeRelay/PERMessage.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,54 @@ +#include "PERMessage.h" + +PERMessage::PERMessage() { + +} + +PERMessage::PERMessage(char contentID, char deviceID, bool rtr, char length, unsigned char* data) { + dataArray[0] = contentID; + dataArray[1] = ((deviceID & 0x7) << 5) | (rtr << 4) | (length & 0xF); + for (int i = 0; i < (length & 0xF); i++) { + dataArray[i+2] = data[i]; + } +} + +char PERMessage::getContentID() { + return dataArray[0]; +} + +char PERMessage::getDeviceID() { + return (dataArray[1] >> 5) & 0x7; +} + +bool PERMessage::getRTR() { + return dataArray[1] & 0x1F; +} + +char PERMessage::getLength() { + return dataArray[1] & 0xF; +} + +void PERMessage::getDataArray(char* buffer) { + for (int i = 0; i < getLength() + 2; i++) { + buffer[i] = dataArray[i]; + } +} +bool PERMessage::setContentID(char contentID) { + dataArray[0] = contentID; + return true; +} + +bool PERMessage::setDeviceID(char deviceID) { + dataArray[1] = dataArray[1] | (deviceID & 0x7) << 5; + return true; +} + +bool PERMessage::setRTR(bool RTR) { + dataArray[1] = dataArray[1] | RTR << 4; + return true; +} + +bool PERMessage::setLength(char length) { + dataArray[1] = dataArray[1] | length & 0xF; + return true; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/xbeeRelay/PERMessage.h Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,26 @@ +#ifndef PERMESSAGE +#define PERMESSAGE + +class PERMessage { + +public: + PERMessage (); + PERMessage (char /* content */, char /* device ID */, bool /* rtr */, char /* length */, unsigned char* /* data[] */); + char getContentID(); + char getDeviceID(); + bool getRTR(); + char getLength(); + void getDataArray(char* /*buffer*/); + + + bool setContentID(char /*contentID*/); + bool setDeviceID(char /*deviceID*/); + bool setRTR(bool /*RTR*/); + bool setLength(char /* Length*/); + + +private: + char dataArray[10]; +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/xbeeRelay/XbeeRelay.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,64 @@ +#include "XbeeRelay.h" +#include "mbed.h" +#include "MODDMA.h" +#include "MODSERIAL.h" +#include "PERMessage.h" + +#define MOTORCONID 0x181 +#define PCMIDLOW 0x200 +#define PCMIDHIGH 0x2FF + +#define MOTORCONSERIALID 0x3 +#define PCMSERIALID 0x2 + +#define DMA_CHANNEL_XBEE_1 0 +#define DMA_CHANNEL_XBEE_2 1 + +XbeeRelay::XbeeRelay() : Xbee_e1(p9,p10), Xbee_e2(p13,p14), counter(0) { + Xbee_e1.baud(250000); + Xbee_e2.baud(250000); + Xbee_e1.MODDMA(&dma); + Xbee_e2.MODDMA(&dma); +} + +bool XbeeRelay::receive(CANMessage cm) { + this->cm = cm; + + XbeeRelay::parse(); + return true;//XbeeRelay::send(); +} + +void XbeeRelay::parseMotorCon () { + unsigned char *dataPtr = cm.data; + PERMessage pm(*dataPtr, MOTORCONSERIALID, false, cm.len - 1, (dataPtr+1)); + this->pm = pm; +} + +void XbeeRelay::parseNormal () { + unsigned char *dataPtr = cm.data; + PERMessage pm(cm.id & 0xFF, (cm.id & 0x700) >> 8, false, cm.len, dataPtr); + this->pm = pm; +} + +void XbeeRelay::parse () { + if (cm.id == MOTORCONID) { + parseMotorCon(); + } else { + parseNormal(); + } +} + +bool XbeeRelay::send () { + char dataarr[pm.getLength() + 2]; + pm.getDataArray(dataarr); + + if (!dma.Enabled(DMA_CHANNEL_XBEE_1)) { + Xbee_e1.dmaSend(dataarr, sizeof(dataarr), DMA_CHANNEL_XBEE_1); + return true; + } else if (!dma.Enabled(DMA_CHANNEL_XBEE_2)) { + Xbee_e2.dmaSend(dataarr, sizeof(dataarr), DMA_CHANNEL_XBEE_2); + return true; + } + + return false; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Libs/xbeeRelay/XbeeRelay.h Fri Nov 14 06:05:59 2014 +0000 @@ -0,0 +1,33 @@ +#ifndef XBEERELAY + +#define XBEERELAY + +#include "mbed.h" +#include "MODDMA.h" +#include "MODSERIAL.h" +#include "PERMessage.h" + + +class XbeeRelay { + +public: + XbeeRelay (); + // returns TRUE on successful send, FALSE otherwise + bool receive(CANMessage /* cm */); + + +private: + void parse(void /* cm */); + void parseMotorCon(void); + void parseNormal(void /* deviceID */); + bool send(void /*pm*/); + char dataLength (char /*contentID*/); + MODSERIAL Xbee_e1; + MODSERIAL Xbee_e2; + unsigned int counter; + MODDMA dma; + CANMessage cm; + PERMessage pm; +}; + +#endif \ No newline at end of file
--- a/main.cpp Thu Nov 13 10:53:10 2014 +0000 +++ b/main.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -1,9 +1,10 @@ #include "IOobjects.h" #include "runTime.h" #include "outDiagnostics.h" +#include "serviceCAN.h" int main() { - wdt.kick(0.11); // Kick the watchdog timer, set the timeout to 110ms + wdt.kick(0.25); // Kick the watchdog timer, set the timeout to 110ms pc.baud(921600); pc.printf("\r\n\r\nSys Mgmt Reset\r\n"); can.mode(FIFO); // Use FIFO mode @@ -24,10 +25,11 @@ // Start the serial, CAN threads Thread serial_out(outDiagnostics::thread_serialOut, 0, osPriorityAboveNormal, 6000); // Allocate 6kB RAM stack - Thread can_out(outDiagnostics::thread_canOut, 0, osPriorityAboveNormal, 256); // Allocate 256B RAM stack + Thread can_out(outDiagnostics::thread_canOut, 0, osPriorityAboveNormal); // Allocate 256B RAM stack // Background task while(1) { // Service CAN and Xbee logic + if (canbus::serviceCAN()); } } \ No newline at end of file
--- a/outDiagnostics/outDiagnostics.cpp Thu Nov 13 10:53:10 2014 +0000 +++ b/outDiagnostics/outDiagnostics.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -1,4 +1,5 @@ #include "outDiagnostics.h" +#include "CAN_TxIDs.h" // Macros for working with the string #define ADD_LINE len+=sprintf(buff+len,"%s\r\n",line); // Add newlines, add it to the working buffer @@ -69,17 +70,17 @@ char switches = data.switchState; const char switchNames[12][26] = {"FUSE","AMS LATCH","IMD LATCH","PCM RELAY","BRAKE PLAUSIBILITY RELAY","LEFT E-STOP","INERTIA SWITCH","BRAKE OVER-TRAVEL SWITCH","COCKPIT E-STOP","RIGHT E-STOP","HVD","TSMS"}; - padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line + padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line padCenter(line, max_charsPerLine-2, " Shutdown Switches ", '*'); ADD_LINE if (switches == 0) sprintf(temp, "All switches are CLOSED."); else sprintf(temp, "%s is OPEN.", switchNames[switches-1]); ADD_SPRINTF_LINE - padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line + /* padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line padCenter(line, max_charsPerLine-2, " Telemetry ", '*'); ADD_LINE sprintf(temp, "Channel 1: MessagesIn: %d MessagesOut: %d", data.xbee1MessagesIn, data.xbee1MessagesOut); ADD_SPRINTF_LINE sprintf(temp, "Channel 2: MessagesIn: %d MessagesOut: %d", data.xbee2MessagesIn, data.xbee2MessagesOut); ADD_SPRINTF_LINE - +*/ padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE // Generate blank line padCenter(line, max_charsPerLine-2, " Miscellaneous ", '*'); ADD_LINE sprintf(temp, "Temp: %5.1fC OverTemp: %s canFault: %s WatchdogReset: %s ErrorFrame: 0x%x", data.internalTemp, BOOL(data.internalOverTemp), BOOL(data.canFault), BOOL(data.watchdogReset), data.errorFrame); ADD_SPRINTF_LINE @@ -88,14 +89,89 @@ for (int i = 0; i < strlen(buff); i++) { pc.putc(buff[i]); } + // Erase screen every 5sec to remove glitches + static int count=0; + if (count%50==0) { + pc.printf("\033[2J"); // Clear the screen + } + count++; Thread::wait(100); } } +template <typename T> +void sendCAN(int ID, T dat) { + CANMessage msg; + msg.id = ID; + msg.len = sizeof(T); + memcpy(&msg.data[0], (void*)&dat, sizeof(T)); + if (!can.txWrite(msg)) data.canFault = true; + xbee.receive(msg); +} + void outDiagnostics::thread_canOut(void const *args) { + while(1) { CANMessage msg; + // Sys Mgmt Error Frame + sendCAN(SYS_ERROR_ID, data.errorFrame); + + // Xbee1 Counter + msg.id = SYS_XBEE1_ID; + msg.len = 2*sizeof(int); + memcpy(&msg.data[0], (void*)&data.xbee1MessagesIn, sizeof(int)); + memcpy(&msg.data[4], (void*)&data.xbee1MessagesOut, sizeof(int)); + if (!can.txWrite(msg)) data.canFault = true; + xbee.receive(msg); + + // Xbee2 Counter + msg.id = SYS_XBEE2_ID; + msg.len = 2*sizeof(int); + memcpy(&msg.data[0], (void*)&data.xbee2MessagesIn, sizeof(int)); + memcpy(&msg.data[4], (void*)&data.xbee2MessagesOut, sizeof(int)); + if (!can.txWrite(msg)) data.canFault = true; + xbee.receive(msg); + + // Internal temperature + sendCAN(SYS_TEMP_ID, data.internalTemp); + + // GLV Battery + sendCAN(SYS_GLV_CURRENT_ID, data.glvCurrent); + sendCAN(SYS_GLV_CAPACITY_ID, data.glvCapacity); + sendCAN(SYS_GLV_AH_ID, data.glvAmphours); + sendCAN(SYS_GLV_SOC_ID, data.glvSOC); + + // DC-DC Converter + sendCAN(SYS_DCDC_CURRENT_ID, data.dcdcCurrent); + sendCAN(SYS_DCDC_STATUS_ID, data.dcdcStatus); + + // PWM Channels + msg.id = SYS_PWM_FAN_ID; + msg.len = 2*sizeof(float); + memcpy(&msg.data[0], (void*)&data.dcdcFan1Duty, sizeof(float)); + memcpy(&msg.data[4], (void*)&data.dcdcFan2Duty, sizeof(float)); + if (!can.txWrite(msg)) data.canFault = true; + xbee.receive(msg); + + msg.id = SYS_PWM_PUMP_ID; + msg.len = 2*sizeof(float); + memcpy(&msg.data[0], (void*)&data.dcdcPump1Duty, sizeof(float)); + memcpy(&msg.data[4], (void*)&data.dcdcPump2Duty, sizeof(float)); + if (!can.txWrite(msg)) data.canFault = true; + xbee.receive(msg); + + // IMD + sendCAN(SYS_IMD_STATUS_ID, data.imdStatus); + sendCAN(SYS_IMD_RESIST_ID, data.imdResistance); + + // Latches + sendCAN(SYS_IMD_LATCH_ID, data.IMDlatchError); + sendCAN(SYS_AMS_LATCH_ID, data.AMSlatchError); + + // Shutdown Switches + sendCAN(SYS_SWITCHES_ID, data.switchState); + Thread::wait(100); } } \ No newline at end of file
--- a/runTime/runTime.cpp Thu Nov 13 10:53:10 2014 +0000 +++ b/runTime/runTime.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -40,11 +40,11 @@ else data.internalOverTemp = false; // Xbees - data.xbee1MessagesIn = xbee1.messagesProcessedIn(); +/* data.xbee1MessagesIn = xbee1.messagesProcessedIn(); data.xbee2MessagesIn = xbee2.messagesProcessedIn(); data.xbee1MessagesOut = xbee1.messagesProcessedOut(); data.xbee2MessagesOut = xbee2.messagesProcessedOut(); - +*/ data.errorFrame = data.canFault<<0 | data.watchdogReset<<1 | data.internalOverTemp<<2 | (data.IMDlatchError!=0)<<3 | (data.AMSlatchError!=0)<<4 | data.imdError<<5 | data.dcdcError<<6 | data.glvOverCurrent<<7; Thread::wait(100); }
--- a/serviceCAN/serviceCAN.cpp Thu Nov 13 10:53:10 2014 +0000 +++ b/serviceCAN/serviceCAN.cpp Fri Nov 14 06:05:59 2014 +0000 @@ -1,25 +1,64 @@ #include "serviceCAN.h" - -// MACRO to setup handling of timeouts -#define TIMEOUT(VAR) Timeout timer_##VAR; void timeout_##VAR(){ flags.VAR = false; } -#define REFRESH_TIMEOUT(VAR) timer_##VAR.detach(); timer_##VAR.attach(&timeout_##VAR, DEVICE_CAN_TIMEOUT/100.0); -#define CHECK_ERRORS(VAR, MSG) if (hasErrors(MSG)) { flags.VAR = false; } else { flags.VAR = true; } - -// Timeouts to handle cases where CAN messages stop coming in - +#include "CAN_RxIDs.h" -// Check every byte of the message for an error bit -bool hasErrors(CANMessage& msg) { - bool errorPresent = false; - for (int i = 0; i < msg.len; i++) { - if (i >= 8) { errorPresent = true; break; } // out of bounds, bad CAN message - if (msg.data[i]) errorPresent = true; - } - return errorPresent; -} bool canbus::serviceCAN() { CANMessage msg; - + if (can.rxRead(msg)) { + switch (msg.id) { + case FAN_CONTROL_ID: + if (msg.len != 2*sizeof(float)) break; + memcpy((void*)&CANdata.dcdcFan1Duty, &msg.data[0], sizeof(float)); + memcpy((void*)&CANdata.dcdcFan2Duty, &msg.data[4], sizeof(float)); + dcdc.setPwm(FAN1, CANdata.dcdcFan1Duty); + dcdc.setPwm(FAN2, CANdata.dcdcFan2Duty); + break; + + case PUMP_CONTROL_ID: + if (msg.len != 2*sizeof(float)) break; + memcpy((void*)&CANdata.dcdcPump1Duty, &msg.data[0], sizeof(float)); + memcpy((void*)&CANdata.dcdcPump2Duty, &msg.data[4], sizeof(float)); + dcdc.setPwm(PUMP1, CANdata.dcdcPump1Duty); + dcdc.setPwm(PUMP2, CANdata.dcdcPump2Duty); + break; + + case DCDC_CONTROL_ID: + if (msg.len != sizeof(char)) break; + if (msg.data[0] == 1) dcdc.set(1); + else dcdc.set(0); + break; + + case AMS_RELAYS_ID: + if (msg.len != sizeof(char)) break; + if ((msg.data[0] & 0xC0) == 0xC0) { + CANdata.airsClosed = true; + dcdc.set(1); + } else { + CANdata.airsClosed = false; + dcdc.set(0); + } + break; + + case GLVBAT_CLEARSOC_ID: + if (msg.len != sizeof(float)) break; + glvBat.resetToSOC(*((float*)(&msg.data[0]))); + break; + + case GLVBAT_CLEARAH_ID: + if (msg.len != sizeof(float)) break; + glvBat.resetToAh(*((float*)(&msg.data[0]))); + break; + + case GLVBAT_SETCAPAC_ID: + if (msg.len != sizeof(float)) break; + glvBat.changeCapacity(*((float*)(&msg.data[0]))); + break; + + default: + break; + } + xbee.receive(msg); + return true; + } return false; } \ No newline at end of file