Uwe Gartmann
/
SBUS-Library_16channel
Futaba S-BUS Library. Let you control 16 servos and 2 digital channels
Revision 0:83e415034198, committed 2012-03-07
- Comitter:
- Digixx
- Date:
- Wed Mar 07 18:18:43 2012 +0000
- Commit message:
Changed in this revision
diff -r 000000000000 -r 83e415034198 FutabaSBUS/FutabaSBUS.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FutabaSBUS/FutabaSBUS.cpp Wed Mar 07 18:18:43 2012 +0000 @@ -0,0 +1,257 @@ +/* mbed R/C Futaba SBUS Library + * Copyright (c) 2011-2012 digixx + * + * 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 "FutabaSBUS.h" +#include "MODSERIAL.h" +#include "mbed.h" + +//debug only +DigitalOut tst1(p8); +DigitalOut tst2(p9); +DigitalOut tst3(p10); + +uint8_t sbus_data[25] = {0x0f,0x01,0x04,0x20,0x00,0xff,0x07,0x40,0x00,0x02,0x10,0x80,0x2c,0x64,0x21,0x0b,0x59,0x08,0x40,0x00,0x02,0x10,0x80,0x00,0x00}; +int16_t channels[18] = {1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,0,0}; +int16_t servos[18] = {1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,0,0}; +uint8_t failsafe_status = SBUS_SIGNAL_FAILSAFE; +bool sbus_passthrough = true; + + +FutabaSBUS::FutabaSBUS(PinName tx, PinName rx) : sbus_(tx, rx) { + // Set Baudrate + sbus_.baud(100000); + // Set Datalenght & Frame + sbus_.format(8, Serial::Even, 2); + // Attach interrupt routines + sbus_.attach(this, &FutabaSBUS::SBUS_irq_rx, MODSERIAL::RxIrq); + // init ticker 500us + rxSBUS.attach_us(this, &FutabaSBUS::rx_ticker_500us,500); + rx_timeout=50; + tx_timeout=60; +} + +int16_t FutabaSBUS::channel(uint8_t ch) { + // Read channel data + if ((ch>0)&&(ch<=16)){ + return channels[ch-1]; + }else{ + return 1023; + } +} + +uint8_t FutabaSBUS::digichannel(uint8_t ch) { + // Read digital channel data + if ((ch>0) && (ch<=2)) { + return channels[15+ch]; + }else{ + return 0; + } +} + +void FutabaSBUS::servo(uint8_t ch, int16_t position) { + // Set servo position + if ((ch>0)&&(ch<=16)) { + if (position>2048) {position=2048;} + servos[ch-1] = position; + } +} + +void FutabaSBUS::digiservo(uint8_t ch, uint8_t position) { + // Set digital servo position + if ((ch>0) && (ch<=2)) { + if (position>1) {position=1;} + servos[15+ch] = position; + } +} + +uint8_t FutabaSBUS::failsafe(void) {return failsafe_status;} + +void FutabaSBUS::passthrough(bool mode) { + // Set passtrough mode, if true, received channel data is send to servos + sbus_passthrough = mode; +} + +bool FutabaSBUS::passthrough(void) { + // Return current passthrough mode + return sbus_passthrough; +} + +/****************************************************************/ +/****************************************************************/ + +void FutabaSBUS::SBUS_irq_rx(MODSERIAL_IRQ_INFO *q) { + rx_timeout=2; + tx_timeout=4; +} + +void FutabaSBUS::update_channels(void) { + // Read all received data and calculate channel data + uint8_t i; + uint8_t sbus_pointer = 0; + while (sbus_.readable()) { + uint8_t data = sbus_.getc(); // get data from serial rx buffer + switch (sbus_pointer) { + case 0: // Byte 1 + if (data==0x0f) { + sbus_data[sbus_pointer] = data; + sbus_pointer++; + } + break; + + case 24: // Byte 25 >> if last byte == 0x00 >> convert data + if (data==0x00) { + sbus_data[sbus_pointer] = data; + // clear channels[] + for (i=0; i<16; i++) {channels[i] = 0;} + + // reset counters + uint8_t byte_in_sbus = 1; + uint8_t bit_in_sbus = 0; + uint8_t ch = 0; + uint8_t bit_in_channel = 0; + + // process actual sbus data + for (i=0; i<176; i++) { + if (sbus_data[byte_in_sbus] & (1<<bit_in_sbus)) { + channels[ch] |= (1<<bit_in_channel); + } + bit_in_sbus++; + bit_in_channel++; + + if (bit_in_sbus == 8) { + bit_in_sbus =0; + byte_in_sbus++; + } + if (bit_in_channel == 11) { + bit_in_channel =0; + ch++; + } + } + // DigiChannel 1 + if (sbus_data[23] & (1<<0)) { + channels[16] = 1; + }else{ + channels[16] = 0; + } + // DigiChannel 2 + if (sbus_data[23] & (1<<1)) { + channels[17] = 1; + }else{ + channels[17] = 0; + } + // Failsafe + failsafe_status = SBUS_SIGNAL_OK; + if (sbus_data[23] & (1<<2)) { + failsafe_status = SBUS_SIGNAL_LOST; + } + if (sbus_data[23] & (1<<3)) { + failsafe_status = SBUS_SIGNAL_FAILSAFE; + } + } + break; + + default: // collect Channel data (11bit) / Failsafe information + sbus_data[sbus_pointer] = data; + sbus_pointer++; + } + } +} + +void FutabaSBUS::update_servos(void) { + // Send data to servos + // Passtrough mode = false >> send own servo data + // Passtrough mode = true >> send received channel data + uint8_t i; + if (!sbus_passthrough) { + // clear received channel data + for (i=1; i<24; i++) { + sbus_data[i] = 0; + } + + // reset counters + uint8_t ch = 0; + uint8_t bit_in_servo = 0; + uint8_t byte_in_sbus = 1; + uint8_t bit_in_sbus = 0; + + // store servo data + for (i=0; i<176; i++) { + if (servos[ch] & (1<<bit_in_servo)) { + sbus_data[byte_in_sbus] |= (1<<bit_in_sbus); + } + bit_in_sbus++; + bit_in_servo++; + + if (bit_in_sbus == 8) { + bit_in_sbus =0; + byte_in_sbus++; + } + if (bit_in_servo == 11) { + bit_in_servo =0; + ch++; + } + } + + // DigiChannel 1 + if (channels[16] == 1) { + sbus_data[23] |= (1<<0); + } + // DigiChannel 2 + if (channels[17] == 1) { + sbus_data[23] |= (1<<1); + } + + // Failsafe + if (failsafe_status == SBUS_SIGNAL_LOST) { + sbus_data[23] |= (1<<2); + } + + if (failsafe_status == SBUS_SIGNAL_FAILSAFE) { + sbus_data[23] |= (1<<2); + sbus_data[23] |= (1<<3); + } + } + // send data out + for (i=0;i<25;i++) { + sbus_.putc(sbus_data[i]); + } +} + +void FutabaSBUS::rx_ticker_500us(void) { + // RX + switch (rx_timeout) { + case 0: + break; + case 1: + if (sbus_.readable()) {update_channels();} + default: + rx_timeout--; + } + // TX + switch (tx_timeout) { + case 0: + update_servos(); + tx_timeout = 28; + default: + tx_timeout--; + } +}
diff -r 000000000000 -r 83e415034198 FutabaSBUS/FutabaSBUS.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FutabaSBUS/FutabaSBUS.h Wed Mar 07 18:18:43 2012 +0000 @@ -0,0 +1,121 @@ +/* mbed R/C Futaba SBUS Library + * Copyright (c) 2011-2012 digixx + * + * 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 MBED_FUTABA_SBUS_H +#define MBED_FUTABA_SBUS_H + +#define SBUS_SIGNAL_OK 0x00 +#define SBUS_SIGNAL_LOST 0x01 +#define SBUS_SIGNAL_FAILSAFE 0x03 + +#include "MODSERIAL.h" +#include "mbed.h" + +/** SBUS control class, based on MODSERIAL + * + * Example: + * @code + * // Continuously sweep the servo through it's full range + * #include "FutabaSBUS.h" + * #include "mbed.h" + * + * FutabaSBUS sbus(p28, p27); + * + * int main() { + * sbus.passthrough(false); + * while(1) { + * for(int i=0; i<100; i++) { + * sbus.servo(1) = i/100.0; + * wait(0.01); + * } + * for(int i=100; i>0; i--) { + * sbus.servo(1) = i/100.0; + * wait(0.01); + * } + * } + * } + * @endcode + */ + +class FutabaSBUS { +public: + /** create a FutabaSBUS object connected to the specified serial pins + * + * ¶m pin serial tx,rx to connect to + */ + FutabaSBUS(PinName tx, PinName rx); + + /** Read channel(1..16), digital raw data + * + * ¶m raw data from receiver range from 0 to 4096, normal from 352 1696 + */ + int16_t channel(uint8_t ch); + + /** Read digital channel(1..2), range 0..1 + * + * ¶m range 0..1 + */ + uint8_t digichannel(uint8_t ch); + + /** Set servo position, raw data, range 200..2000? + * + * ¶m raw data 0..2048 + */ + void servo(uint8_t ch, int16_t position); + + /** Set digital channel, 0..1 + * + * ¶m range 0..1 + */ + void digiservo(uint8_t ch, uint8_t position); + + /** Read failsafe condition + * + * ¶m 0=no failsafe 1=lost signal 3=failsafe + */ + uint8_t failsafe(void); + + /** Set logical data passtrough - servo values are ignored, using received data + * + * ¶m bool + */ + void passthrough(bool mode); + + /** Read logical data passtrough + * + * ¶m bool + */ + bool passthrough(void); + +private: + MODSERIAL sbus_; + Ticker rxSBUS; + void SBUS_irq_rx(MODSERIAL_IRQ_INFO *q); + void rx_ticker_500us(void); + void update_channels(void); + void update_servos(void); + volatile int rx_timeout; + volatile int tx_timeout; +}; + +#endif \ No newline at end of file
diff -r 000000000000 -r 83e415034198 MODSERIAL/ChangeLog.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/ChangeLog.c Wed Mar 07 18:18:43 2012 +0000 @@ -0,0 +1,153 @@ +/* $Id:$ + +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
diff -r 000000000000 -r 83e415034198 MODSERIAL/FLUSH.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/FLUSH.cpp Wed Mar 07 18:18:43 2012 +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
diff -r 000000000000 -r 83e415034198 MODSERIAL/GETC.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/GETC.cpp Wed Mar 07 18:18:43 2012 +0000 @@ -0,0 +1,63 @@ +/* + 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; + } + + buffer_count[RxIrq]--; + return c; +} + +}; // namespace AjK ends
diff -r 000000000000 -r 83e415034198 MODSERIAL/INIT.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/INIT.cpp Wed Mar 07 18:18:43 2012 +0000 @@ -0,0 +1,74 @@ +/* + 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) +{ + disableIrq(); + + callbackInfo.setSerial(this); + + switch(_uidx) { + 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; + } + + 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
diff -r 000000000000 -r 83e415034198 MODSERIAL/ISR_RX.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/ISR_RX.cpp Wed Mar 07 18:18:43 2012 +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 +
diff -r 000000000000 -r 83e415034198 MODSERIAL/ISR_TX.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/ISR_TX.cpp Wed Mar 07 18:18:43 2012 +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 + +
diff -r 000000000000 -r 83e415034198 MODSERIAL/MACROS.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/MACROS.h Wed Mar 07 18:18:43 2012 +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
diff -r 000000000000 -r 83e415034198 MODSERIAL/MODSERIAL.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/MODSERIAL.cpp Wed Mar 07 18:18:43 2012 +0000 @@ -0,0 +1,128 @@ +/* + 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); +} + +MODSERIAL::MODSERIAL(PinName tx, PinName rx, int bufferSize, const char *name) : Serial(tx, rx, name) +{ + init(bufferSize, bufferSize); +} + +MODSERIAL::MODSERIAL(PinName tx, PinName rx, int txSize, int rxSize, const char *name) : Serial(tx, rx, name) +{ + init(txSize, rxSize); +} + +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) +{ + switch(_uidx) { + 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; + } +} + +void +MODSERIAL::enableIrq(void) +{ + switch(_uidx) { + 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; + } +} + +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
diff -r 000000000000 -r 83e415034198 MODSERIAL/MODSERIAL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/MODSERIAL.h Wed Mar 07 18:18:43 2012 +0000 @@ -0,0 +1,1091 @@ +/* + 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" + +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. + * @param name An option name for RPC usage. + */ + 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. + * @param name An option name for RPC usage. + */ + 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. + * @param name An option name for RPC usage. + */ + 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); + + /** + * 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(_uidx) { + 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
diff -r 000000000000 -r 83e415034198 MODSERIAL/MODSERIAL_IRQ_INFO.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/MODSERIAL_IRQ_INFO.cpp Wed Mar 07 18:18:43 2012 +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
diff -r 000000000000 -r 83e415034198 MODSERIAL/PUTC.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/PUTC.cpp Wed Mar 07 18:18:43 2012 +0000 @@ -0,0 +1,79 @@ +/* + 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; + buffer_count[TxIrq]++; + buffer_in[TxIrq]++; + if (buffer_in[TxIrq] >= buffer_size[TxIrq]) { + buffer_in[TxIrq] = 0; + } + _IER |= 2; + } + + return 0; +} + +}; // namespace AjK ends
diff -r 000000000000 -r 83e415034198 MODSERIAL/RESIZE.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/RESIZE.cpp Wed Mar 07 18:18:43 2012 +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
diff -r 000000000000 -r 83e415034198 TextLCD/TextLCD.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TextLCD/TextLCD.cpp Wed Mar 07 18:18:43 2012 +0000 @@ -0,0 +1,164 @@ +/* mbed TextLCD Library, for a 4-bit LCD based on HD44780 + * Copyright (c) 2007-2010, sford, http://mbed.org + * + * 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 "TextLCD.h" +#include "mbed.h" + +TextLCD::TextLCD(PinName rs, PinName rw, PinName e, PinName d4, PinName d5, + PinName d6, PinName d7, LCDType type) : _rs(rs), _rw(rw), + _e(e), _d(d4, d5, d6, d7), + _type(type) { + + _rw = 0; + _e = 1; + _rs = 0; // command mode + + wait(0.015); // Wait 15ms to ensure powered up + + // send "Display Settings" 3 times (Only top nibble of 0x30 as we've got 4-bit bus) + for (int i=0; i<3; i++) { + writeNibble(0x3); + wait(0.00164); // this command takes 1.64ms, so wait for it + } + + writeNibble(0x2); // 4-bit mode + + writeCommand(0x28); // Function set 001 BW N F - - + writeCommand(0x0C); + writeCommand(0x6); // Cursor Direction and Display Shift : 0000 01 CD S (CD 0-left, 1-right S(hift) 0-no, 1-yes + cls(); +} + +void TextLCD::character(int column, int row, int c) { + int a = address(column, row); + writeCommand(a); + writeData(c); +} + +void TextLCD::cls() { + writeCommand(0x01); // cls, and set cursor to 0 + wait(0.00164f); // This command takes 1.64 ms + locate(0, 0); +} + +void TextLCD::locate(int column, int row) { + _column = column; + _row = row; +} + +int TextLCD::_putc(int value) { + if (value == '\n') { + _column = 0; + _row++; + if (_row >= rows()) { + _row = 0; + } + } else { + character(_column, _row, value); + _column++; + if (_column >= columns()) { + _column = 0; + _row++; + if (_row >= rows()) { + _row = 0; + } + } + } + return value; +} + +int TextLCD::_getc() { + return -1; +} + +void TextLCD::writeByte(int value) { + writeNibble(value >> 4); + writeNibble(value >> 0); +} + +void TextLCD::writeCommand(int command) { + _rs = 0; + writeByte(command); +} + +void TextLCD::clock(void) { + wait(0.000040f); + _e = 0; + wait(0.000040f); + _e = 1; +} + +void TextLCD::writeNibble(int data) { + _d = data; + clock(); +} + +void TextLCD::writeData(int data) { + _rs = 1; + writeByte(data); +} + +int TextLCD::address(int column, int row) { + switch (_type) { + case LCD20x4: + switch (row) { + case 0: + return 0x80 + column; + case 1: + return 0xc0 + column; + case 2: + return 0x94 + column; + case 3: + return 0xd4 + column; + } + case LCD16x2B: + return 0x80 + (row * 40) + column; + case LCD16x2: + case LCD20x2: + default: + return 0x80 + (row * 0x40) + column; + } +} + +int TextLCD::columns() { + switch (_type) { + case LCD20x4: + case LCD20x2: + return 20; + case LCD16x2: + case LCD16x2B: + default: + return 16; + } +} + +int TextLCD::rows() { + switch (_type) { + case LCD20x4: + return 4; + case LCD16x2: + case LCD16x2B: + case LCD20x2: + default: + return 2; + } +}
diff -r 000000000000 -r 83e415034198 TextLCD/TextLCD.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TextLCD/TextLCD.h Wed Mar 07 18:18:43 2012 +0000 @@ -0,0 +1,113 @@ +/* mbed TextLCD Library, for a 4-bit LCD based on HD44780 + * Copyright (c) 2007-2010, sford, http://mbed.org + * + * 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 MBED_TEXTLCD_H +#define MBED_TEXTLCD_H + +#include "mbed.h" + +/** A TextLCD interface for driving 4-bit HD44780-based LCDs + * + * Currently supports 16x2, 20x2 and 20x4 panels + * + * @code + * #include "mbed.h" + * #include "TextLCD.h" + * + * TextLCD lcd(p10, p12, p15, p16, p29, p30); // rs, e, d4-d7 + * + * int main() { + * lcd.printf("Hello World!\n"); + * } + * @endcode + */ +class TextLCD : public Stream { +public: + + /** LCD panel format */ + enum LCDType { + LCD16x2 /**< 16x2 LCD panel (default) */ + , LCD16x2B /**< 16x2 LCD panel alternate addressing */ + , LCD20x2 /**< 20x2 LCD panel */ + , LCD20x4 /**< 20x4 LCD panel */ + }; + + /** Create a TextLCD interface + * + * @param rs Instruction/data control line + * @param e Enable line (clock) + * @param d4-d7 Data lines for using as a 4-bit interface + * @param type Sets the panel size/addressing mode (default = LCD16x2) + */ + TextLCD(PinName rs, PinName rw, PinName e, PinName d4, PinName d5, PinName d6, PinName d7, LCDType type = LCD16x2); + +#if DOXYGEN_ONLY + /** Write a character to the LCD + * + * @param c The character to write to the display + */ + int putc(int c); + + /** Write a formated string to the LCD + * + * @param format A printf-style format string, followed by the + * variables to use in formating the string. + */ + int printf(const char* format, ...); +#endif + + /** Locate to a screen column and row + * + * @param column The horizontal position from the left, indexed from 0 + * @param row The vertical position from the top, indexed from 0 + */ + void locate(int column, int row); + + /** Clear the screen and locate to 0,0 */ + void cls(); + + int rows(); + int columns(); + +protected: + + // Stream implementation functions + virtual int _putc(int value); + virtual int _getc(); + + int address(int column, int row); + void character(int column, int row, int c); + void writeByte(int value); + void writeCommand(int command); + void writeData(int data); + void writeNibble(int data); + void clock(void); + + DigitalOut _rs, _rw, _e; + BusOut _d; + LCDType _type; + + int _column; + int _row; +}; + +#endif
diff -r 000000000000 -r 83e415034198 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Wed Mar 07 18:18:43 2012 +0000 @@ -0,0 +1,52 @@ +#include "FutabaSBUS.h" +#include "TextLCD.h" +#include "mbed.h" + +DigitalOut mled(LED4); +TextLCD lcd(p26, p25, p24, p23, p22, p20, p19, TextLCD::LCD20x4); +FutabaSBUS sbus(p28, p27); + + +int main() { + sbus.passthrough(false); + while (1) { + sbus.servo(1,200); + wait(0.5); + sbus.servo(1,1700); + wait(0.5); + mled=!mled; + + lcd.locate(0,0); + lcd.printf("fs:"); + lcd.printf("%i",sbus.failsafe()); + lcd.printf(" "); + + lcd.locate(0,1); + lcd.printf("dg:"); + lcd.printf("%i",sbus.digichannel(1)); + lcd.printf("#"); + lcd.printf("%i",sbus.digichannel(2)); + lcd.printf(" "); + + lcd.locate(0,2); + lcd.printf("Q:"); + lcd.printf("%i",sbus.channel(1)); + lcd.printf(" "); + + lcd.locate(10,2); + lcd.printf("H:"); + lcd.printf("%i",sbus.channel(2)); + lcd.printf(" "); + + lcd.locate(0,3); + lcd.printf("G:"); + lcd.printf("%i",sbus.channel(3)); + lcd.printf(" "); + + lcd.locate(10,3); + lcd.printf("S:"); + lcd.printf("%i",sbus.channel(4)); + lcd.printf(" "); + + } +}
diff -r 000000000000 -r 83e415034198 mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Wed Mar 07 18:18:43 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/078e4b97a13e