
BeaconAvoid code for AHRC competition.
Dependencies: MODSERIAL PiSlingers m3pi mbed
Revision 0:9ac4a91b71fa, committed 2012-04-04
- Comitter:
- mpanetta
- Date:
- Wed Apr 04 17:07:49 2012 +0000
- Child:
- 1:ac4eff391f12
- Commit message:
- Initial commit. Avoidance code complete, beacon code still needs to be added.
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IRBehaviorController.cpp Wed Apr 04 17:07:49 2012 +0000 @@ -0,0 +1,99 @@ +#include "mbed.h" + +#include "IRBehaviorController.h" + + +// Public methods + +void +IRBehaviorController::setActiveThreshold(float threshold) +{ + NVIC_DisableIRQ(TIMER3_IRQn); // Disable Ticker IRQ for atomicity + activationThreshold = threshold; + NVIC_EnableIRQ(TIMER3_IRQn); // Enable Ticker IRQ +} + + +void +IRBehaviorController::runSeeking(void) +{ + if (debug != NULL) + debug->printf("IRController: Seeking Task Start.\r\n"); + + scanIR(); + + if (brightness > activationThreshold) + output = pid->run(centeroid); + else + output = 0; + + if (debug != NULL) + debug->printf("IRController: Seeking Task Complete.\r\n"); +} + +void +IRBehaviorController::runAvoidance(void) +{ + if (debug != NULL) + debug->printf("IRController: Avoidance Task Start.\r\n"); + + scanIR(); + + // Centeroid value needs to be split for avoidance mode. + if (centeroid < 0) + centeroid += 3; + else + centeroid -=3; + + if (brightness > activationThreshold) + output = pid->run(centeroid); + else + output = 0; + + if (debug != NULL) + debug->printf("IRController: Avoidance Task Complete.\r\n"); +} + +float +IRBehaviorController::getPower(void) +{ + float tmp; + + NVIC_DisableIRQ(TIMER3_IRQn); // Disable Ticker IRQ for atomicity + tmp = output; + NVIC_EnableIRQ(TIMER3_IRQn); // Enable Ticker IRQ + + return tmp; +} + +void +IRBehaviorController::dumpDebug(Serial *debug) +{ + if (debug != NULL) + { + debug->printf("IRController: Centeroid = %3.2f\r\n", centeroid); + debug->printf("IRController: Brightness = %3.2f\r\n", brightness); + debug->printf("IRController: Power = %3.2f\r\n", output); + } +} + +// Private methods + +void +IRBehaviorController::scanIR(void) +{ + if (debug != NULL) + debug->printf("IRController: Scanning IR.\r\n"); + + ird.scan(); + + centeroid = ird.get_centeroid(); + brightness = ird.get_weighted_avg_brightness(); + + if (debug != NULL) + { + debug->printf("IRController: Scan complete.\r\n"); + debug->printf("IRController: Centeroid = %3.2f\r\n", centeroid); + debug->printf("IRController: Brightness = %3.2f\r\n", brightness); + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IRBehaviorController.h Wed Apr 04 17:07:49 2012 +0000 @@ -0,0 +1,54 @@ +#ifndef __IRBEHAVIORCONTROLLER_H__ +#define __IRBEHAVIORCONTROLLER_H__ + +#include "mbed.h" +#include "IRObjDetector.h" +#include "PID.h" + +class IRBehaviorController +{ +public: + IRBehaviorController(PID *pid) : pid(pid) + { + debug = NULL; + activationThreshold = 0.0f; + brightness = 0.0f; + output = 0.0f; + }; + + IRBehaviorController(PID * pid, Serial * debug) : debug(debug), ird(debug), pid(pid) + //IRBehaviorController(PID * pid, Serial * debug) : debug(debug), pid(pid) + { + activationThreshold = 0.0f; + brightness = 0.0f; + output = 0.0f; + }; + + void setAvoidanceBehavior(float threshold); + void setSeekingBehavior(float threshold); + + void setActiveThreshold(float threshold); // Brightness level at which behavior is active. + + void runAvoidance(void); // Execute avoidance behavior + void runSeeking(void); // Execute seeking behavior + + float getPower(void); // Returns the power value needed to execute the behavior. + + void dumpDebug(Serial *debug); + +private: + + void scanIR(void); + + Serial *debug; + + IRObjDetector ird; + PID *pid; + + float activationThreshold; // Brightness threshold at which behavior is active. + float brightness; + float centeroid; + + float output; +}; +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/.lib Wed Apr 04 17:07:49 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/AjK/libraries/MODSERIAL/lqybn0 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/ChangeLog.c Wed Apr 04 17:07:49 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/FLUSH.cpp Wed Apr 04 17:07:49 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/GETC.cpp Wed Apr 04 17:07:49 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/INIT.cpp Wed Apr 04 17:07:49 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/ISR_RX.cpp Wed Apr 04 17:07:49 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 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/ISR_TX.cpp Wed Apr 04 17:07:49 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 + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/MACROS.h Wed Apr 04 17:07:49 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/MODSERIAL.cpp Wed Apr 04 17:07:49 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/MODSERIAL.h Wed Apr 04 17:07:49 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/MODSERIAL_IRQ_INFO.cpp Wed Apr 04 17:07:49 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/PUTC.cpp Wed Apr 04 17:07:49 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODSERIAL/RESIZE.cpp Wed Apr 04 17:07:49 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PID.cpp Wed Apr 04 17:07:49 2012 +0000 @@ -0,0 +1,103 @@ +#include "PID.h" + +void +PID::setP(float p) +{ + NVIC_DisableIRQ(TIMER3_IRQn); // Disable Ticker IRQ for atomicity + k_p = p; + NVIC_EnableIRQ(TIMER3_IRQn); // Enable Ticker IRQ +} + +void +PID::setI(float i) +{ + NVIC_DisableIRQ(TIMER3_IRQn); // Disable Ticker IRQ for atomicity + k_i = i; + NVIC_EnableIRQ(TIMER3_IRQn); // Enable Ticker IRQ +} + +void +PID::setD(float d) +{ + NVIC_DisableIRQ(TIMER3_IRQn); // Disable Ticker IRQ for atomicity + k_d = d; + NVIC_EnableIRQ(TIMER3_IRQn); // Enable Ticker IRQ +} + +void +PID::setClip(float clip) +{ + NVIC_DisableIRQ(TIMER3_IRQn); // Disable Ticker IRQ for atomicity + this->clip = clip; + NVIC_EnableIRQ(TIMER3_IRQn); // Enable Ticker IRQ +} + +void +PID::setPV(float pv) // Set process variable +{ + NVIC_DisableIRQ(TIMER3_IRQn); // Disable Ticker IRQ for atomicity + error = pv; + NVIC_EnableIRQ(TIMER3_IRQn); // Enable Ticker IRQ + +} + +void +PID::dumpDebug(Serial *debug) +{ + if (debug != NULL) + { + debug->printf("PID Debug: v_p = %3.2f\r\n", v_p); + debug->printf("PID Debug: v_i = %3.2f\r\n", v_i); + debug->printf("PID Debug: v_d = %3.2f\r\n", v_d); + debug->printf("PID Debug: k_p = %3.2f\r\n", k_p); + debug->printf("PID Debug: k_i = %3.2f\r\n", k_i); + debug->printf("PID Debug: k_d = %3.2f\r\n", k_d); + debug->printf("PID Debug: clip = %3.2f\r\n", clip); + debug->printf("PID Debug: error = %3.2f\r\n", error); + debug->printf("PID Debug: prev_error = %3.2f\r\n", prev_error); + debug->printf("PID Debug: output = %3.2f\r\n", output); + } +} + +float +PID::run(float in) +{ + if (debug != NULL) + debug->printf("PID Debug: in = %3.2f\r\n", in); + error = in; + + v_p = error; + v_i += v_p; + v_d = error - prev_error; + + if (v_i > clip) + v_i = clip; + if (v_i < clip) + v_i = -clip; + if (v_i != v_i) // NAN check... + v_i = 0; + + if (debug != NULL) + { + debug->printf("PID Debug: v_p = %3.2f\r\n", v_p); + debug->printf("PID Debug: v_i = %3.2f\r\n", v_i); + debug->printf("PID Debug: v_d = %3.2f\r\n", v_d); + debug->printf("PID Debug: k_p = %3.2f\r\n", k_p); + debug->printf("PID Debug: k_i = %3.2f\r\n", k_i); + debug->printf("PID Debug: k_d = %3.2f\r\n", k_d); + debug->printf("PID Debug: clip = %3.2f\r\n", clip); + } + + output = (v_p * k_p) + (v_i * k_i) + (v_d * k_d); + + if (debug != NULL) + { + debug->printf("PID Debug: error = %3.2f\r\n", error); + debug->printf("PID Debug: prev_error = %3.2f\r\n", prev_error); + debug->printf("PID Debug: output = %3.2f\r\n", output); + } + + prev_error = error; + + return output; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PID.h Wed Apr 04 17:07:49 2012 +0000 @@ -0,0 +1,59 @@ +#ifndef __PID_H__ +#define __PID_H__ + +#include "mbed.h" + +class PID +{ +public: + PID(float i_p, float i_i, float i_d) : + k_p(i_p), k_i(i_i), k_d(i_d) + { + debug = NULL; + + v_p = 0.0f; + v_i = 0.0f; + v_d = 0.0f; + + clip = 1.0f; + error = 0.0f; + prev_error = 0.0f; + } + + PID(float i_p, float i_i, float i_d, Serial *debug) : + debug(debug), k_p(i_p), k_i(i_i), k_d(i_d) + { + v_p = 0.0f; + v_i = 0.0f; + v_d = 0.0f; + + clip = 1.0f; + error = 0.0f; + prev_error = 0.0f; + } + + void setP(float p); // set k_p + void setI(float i); // set k_i + void setD(float d); // set k_d + void setClip(float clip); + void setPV(float pv); // Set process variable (PID input) + float getOutput(void); // Get PID output. + + void run(void); // Callback to be called via Ticker to execute the PID algo. + float run(float in); // Version to run PID in place (not via timer or interrupt) + + void dumpDebug(Serial *debug); + +private: + Serial *debug; + + float k_p, k_i, k_d; // PID constants + float v_p, v_i, v_d; // PID variables + float clip; // Integral clip value (absolute) + float error; + float prev_error; + float output; + +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PiSlingers/.lib Wed Apr 04 17:07:49 2012 +0000 @@ -0,0 +1,1 @@ + \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PiSlingers/Beacon.cpp Wed Apr 04 17:07:49 2012 +0000 @@ -0,0 +1,49 @@ +#include "Beacon.h" + +void +Beacon::scan(void) +{ + valL = ainL.read_u16() >> 8; + valR = ainR.read_u16() >> 8; +// valR = ainL.read_u16() >> 8; +// valL = ainR.read_u16() >> 8; + + valL > valR ? max = valL : max = valR; + + calc_centeroid(); +} + +void +Beacon::calc_centeroid(void) +{ + float sumA, sumB; + + sumB = (valL * 1) + (valR * 2); + sumA = valL + valR; + + centeroid = sumB / sumA - 1.5f; +} + +float +Beacon::get_centeroid(void) +{ + return centeroid; +} + +uint8_t +Beacon::get_max_rssi(void) +{ + return max; +} + +uint8_t +Beacon::getL(void) +{ + return valL; +} + +uint8_t +Beacon::getR(void) +{ + return valR; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PiSlingers/Beacon.h Wed Apr 04 17:07:49 2012 +0000 @@ -0,0 +1,32 @@ +#ifndef _BEACON_H_ +#define _BEACON_H_ + +#include "mbed.h" + +class Beacon +{ +public: + Beacon(void) : ainL(p19), ainR(p20) {}; + + void scan(void); + uint8_t get_max_rssi(void); + float get_centeroid(void); + + uint8_t getL(void); + uint8_t getR(void); + +private: + void calc_centeroid(void); + + AnalogIn ainL; + AnalogIn ainR; + + uint8_t valL; + uint8_t valR; + + uint8_t max; + float centeroid; + +}; + +#endif //_BEACON_H_ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PiSlingers/IRObjDetector.cpp Wed Apr 04 17:07:49 2012 +0000 @@ -0,0 +1,132 @@ +#include "IRObjDetector.h" +#include "tlc5916.h" + +#define DWELL_TIME 25 // Time to wait between enabling IR transmitter LED and reading ADC result, in us. + +void +IRObjDetector::scan(void) +{ + int i; + uint32_t max = 0; + int32_t tmp; + + //data[7] = ain.read_u16() >> 8; // Read the ambient level and store in last data slot. + data[7] = ain.read_u16(); // Read the ambient level and store in last data slot. + + // Set the IR leds one at a time and read the reflection. + for (i = 0; i < 7; i++) + { + // Write the value to enable the LED + tlc5916.write_reg(1 << i); + // Enable the selected LED. + tlc5916.enable(); + // Wait for output to stabilize + wait_us(DWELL_TIME); + // Read ADC value and subtract off ambient. + //tmp = (ain.read_u16() >> 8) - data[7]; + tmp = ain.read_u16() - data[7]; + if (tmp < 0) + data[i] = 0; + else + data[i] = tmp >> 8; + // Disable the selected LED. + tlc5916.disable(); + + if (tmp > max) max = tmp; + } + + calc_centeroid(); + + brightness = max; + + brightnessBins[currentBin++] = brightness; + + // Calculate running average over BRIGHTNESS_BINS bins. + minBrightness = 0xFFFF; + avgBrightness = 0; + maxBrightness = 0; + for (int i = 0; i < BRIGHTNESS_BINS; i++) + { + tmp = brightnessBins[i]; + if (minBrightness > tmp) minBrightness = tmp; + avgBrightness += tmp; + if (maxBrightness < tmp) maxBrightness = tmp; + } + avgBrightness = avgBrightness / BRIGHTNESS_BINS; + + if (currentBin >= BRIGHTNESS_BINS) + currentBin = 0; +} + +float +IRObjDetector::get_weighted_avg_brightness(void) +{ + if (debug != NULL) + { + debug->printf("IRObjDetector: Calculating weighted average.\r\n"); + debug->printf("IRObjDetector: minBrightness = 0x%4.4x\r\n", minBrightness); + debug->printf("IRObjDetector: avgBrightness = 0x%4.4x\r\n", avgBrightness); + debug->printf("IRObjDetector: minBrightness = 0x%4.4x\r\n", maxBrightness); + } + return (float)(avgBrightness) / (float)0xffff; +} + +void +IRObjDetector::calc_centeroid(void) +{ + int i; + + uint32_t low; + float sumA, sumB; + + low = 0xffff; + for (i = 0; i < 7; i++) + { + if (data[i] < low) low = data[i]; + } + + sumA = sumB = 0; + + // Generate sums for centeroid data + for (i = 0; i < 7; i++) + { + sumB += (data[i] - low) * (i + 1); + sumA += data[i] - low; + } + + // Get 'center' bin by taking the highest bin count and dividing by number of bins. + float offset = 28/7; + + centeroid = sumB / sumA; // Generate centroid (approximate location of object) which is a number between 1 an nBins (7 in our case) + centeroid -= offset; // Offset the centeroid around center bin, now the centeroid is a number between 1-offset and offset-1 (-3 to 3 in our case) +} + +float +IRObjDetector::get_centeroid(void) +{ + return centeroid; +} + +uint16_t +IRObjDetector::get_raw_brightness(void) +{ + return brightness; +} + +uint16_t +IRObjDetector::get_min_brightness(void) +{ + return minBrightness; +} + +uint16_t +IRObjDetector::get_avg_brightness(void) +{ + return avgBrightness; +} + +uint16_t +IRObjDetector::get_max_brightness(void) +{ + return maxBrightness; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PiSlingers/IRObjDetector.h Wed Apr 04 17:07:49 2012 +0000 @@ -0,0 +1,79 @@ +#ifndef _IROBJDETECTOR_H_ +#define _IROBJDETECTOR_H_ + +#include "mbed.h" +#include "tlc5916.h" + +#define BRIGHTNESS_BINS 16 + +class IRObjDetector +{ +public: + IRObjDetector(void) : tlc5916(p6, p5, p7, p11), ain(p18) + { + debug = NULL; + minBrightness = 0; + avgBrightness = 0; + maxBrightness = 0; + for (currentBin = 0; currentBin < BRIGHTNESS_BINS; currentBin++) + { + brightnessBins[currentBin] = 0; + } + currentBin = 0; + }; + + IRObjDetector(Serial *debug) : debug(debug), tlc5916(p6, p5, p7, p11), ain(p18) + { + debug = NULL; + minBrightness = 0; + avgBrightness = 0; + maxBrightness = 0; + for (currentBin = 0; currentBin < BRIGHTNESS_BINS; currentBin++) + { + brightnessBins[currentBin] = 0; + } + currentBin = 0; + }; + + /** + * Scan through all 7 LED's and store the values. + */ + void scan(void); + + /** + * Get the centeroid value of the scaned field. + */ + float get_centeroid(void); + + /** + * Get the 'raw' brightness value. + */ + uint16_t get_raw_brightness(void); + uint16_t get_min_brightness(void); + uint16_t get_avg_brightness(void); + uint16_t get_max_brightness(void); + float get_weighted_avg_brightness(void); + +private: + + void calc_centeroid(void); + void calc_contrast(void); + + Serial *debug; + TLC5916 tlc5916; + AnalogIn ain; + uint16_t data[8]; //Bin 7 is the 'all off' bin. + float centeroid; + uint16_t brightness; + uint16_t brightnessBins[BRIGHTNESS_BINS]; // Used to calculate average brightness + uint8_t currentBin; + uint32_t avgBrightness; + uint16_t maxBrightness; + uint16_t minBrightness; + + + float mean; + float map; +}; + +#endif //_IROBJDETECTOR_H_ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PiSlingers/tlc5916.cpp Wed Apr 04 17:07:49 2012 +0000 @@ -0,0 +1,26 @@ + +#include "mbed.h" +#include "tlc5916.h" + +void +TLC5916::write_reg(uint8_t byte) +{ + pinLE = 0; + spi.write(byte); + wait_us(1); + pinLE = 1; + wait_us(1); + pinLE = 0; +} + +void +TLC5916::enable(void) +{ + pinnOE = 0; +} + +void +TLC5916::disable(void) +{ + pinnOE = 1; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PiSlingers/tlc5916.h Wed Apr 04 17:07:49 2012 +0000 @@ -0,0 +1,28 @@ +#ifndef _TLC5916_H_ +#define _TLC5916_H_ + +class TLC5916 { + +public: + TLC5916(PinName le, PinName sin, PinName clk, PinName nOE) : pinLE(le), pinnOE(nOE), spi(sin, NC, clk) + { + pinLE = 0; + pinnOE = 1; + + spi.format(8,0); + spi.frequency(1000000); + }; + + void write_reg(uint8_t byte); + void enable(void); + void disable(void); + +private: + + DigitalOut pinLE; + DigitalOut pinnOE; + SPI spi; + +}; + +#endif //_TLC5916_H_ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/m3pi/.lib Wed Apr 04 17:07:49 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/chris/libraries/m3pi/lr20a4 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/m3pi/m3pi.cpp Wed Apr 04 17:07:49 2012 +0000 @@ -0,0 +1,238 @@ +/* m3pi Library + * + * Copyright (c) 2007-2010 cstyles + * + * 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 "mbed.h" +#include "m3pi.h" + +m3pi::m3pi(PinName nrst, PinName tx, PinName rx) : Stream("m3pi"), _nrst(nrst), _ser(tx, rx) { + _ser.baud(115200); + reset(); +} + +m3pi::m3pi() : Stream("m3pi"), _nrst(p23), _ser(p9, p10) { + _ser.baud(115200); + reset(); +} + + +void m3pi::reset () { + _nrst = 0; + wait (0.01); + _nrst = 1; + wait (0.1); +} + +void m3pi::left_motor (float speed) { + motor(0,speed); +} + +void m3pi::right_motor (float speed) { + motor(1,speed); +} + +void m3pi::forward (float speed) { + motor(0,speed); + motor(1,speed); +} + +void m3pi::backward (float speed) { + motor(0,-1.0*speed); + motor(1,-1.0*speed); +} + +void m3pi::left (float speed) { + motor(0,speed); + motor(1,-1.0*speed); +} + +void m3pi::right (float speed) { + motor(0,-1.0*speed); + motor(1,speed); +} + +void m3pi::stop (void) { + motor(0,0.0); + motor(1,0.0); +} + +void m3pi::motor (int motor, float speed) { + char opcode = 0x0; + if (speed > 0.0) { + if (motor==1) + opcode = M1_FORWARD; + else + opcode = M2_FORWARD; + } else { + if (motor==1) + opcode = M1_BACKWARD; + else + opcode = M2_BACKWARD; + } + unsigned char arg = 0x7f * abs(speed); + + _ser.putc(opcode); + _ser.putc(arg); +} + +float m3pi::battery() { + _ser.putc(SEND_BATTERY_MILLIVOLTS); + char lowbyte = _ser.getc(); + char hibyte = _ser.getc(); + float v = ((lowbyte + (hibyte << 8))/1000.0); + return(v); +} + +float m3pi::line_position() { + int pos = 0; + _ser.putc(SEND_LINE_POSITION); + pos = _ser.getc(); + pos += _ser.getc() << 8; + + float fpos = ((float)pos - 2048.0)/2048.0; + return(fpos); +} + +const m3pi::LineSensors m3pi::get_raw_sensors(void) { + static LineSensors sensors; + + _ser.putc(SEND_RAW_SENSOR_VALUES); + + sensors.sensor1 = _ser.getc(); + sensors.sensor1 |= _ser.getc() << 8; + sensors.sensor2 = _ser.getc(); + sensors.sensor2 |= _ser.getc() << 8; + sensors.sensor3 = _ser.getc(); + sensors.sensor3 |= _ser.getc() << 8; + sensors.sensor4 = _ser.getc(); + sensors.sensor4 |= _ser.getc() << 8; + sensors.sensor5 = _ser.getc(); + sensors.sensor5 |= _ser.getc() << 8; + + return sensors; +} + +char m3pi::sensor_auto_calibrate() { + _ser.putc(AUTO_CALIBRATE); + return(_ser.getc()); +} + + +void m3pi::calibrate(void) { + _ser.putc(PI_CALIBRATE); +} + +void m3pi::reset_calibration() { + _ser.putc(LINE_SENSORS_RESET_CALIBRATION); +} + +void m3pi::PID_start(int max_speed, int a, int b, int c, int d) { + _ser.putc(max_speed); + _ser.putc(a); + _ser.putc(b); + _ser.putc(c); + _ser.putc(d); +} + +void m3pi::PID_stop() { + _ser.putc(STOP_PID); +} + +float m3pi::pot_voltage(void) { + int volt = 0; + _ser.putc(SEND_TRIMPOT); + volt = _ser.getc(); + volt += _ser.getc() << 8; + return(volt); +} + + +void m3pi::leds(int val) { + + BusOut _leds(p20,p19,p18,p17,p16,p15,p14,p13); + _leds = val; +} + + +void m3pi::locate(int x, int y) { + _ser.putc(DO_LCD_GOTO_XY); + _ser.putc(x); + _ser.putc(y); +} + +void m3pi::cls(void) { + _ser.putc(DO_CLEAR); +} + +int m3pi::print (char* text, int length) { + _ser.putc(DO_PRINT); + _ser.putc(length); + for (int i = 0 ; i < length ; i++) { + _ser.putc(text[i]); + } + return(0); +} + +int m3pi::_putc (int c) { + _ser.putc(DO_PRINT); + _ser.putc(0x1); + _ser.putc(c); + wait (0.001); + return(c); +} + +int m3pi::_getc (void) { + char r = 0; + return(r); +} + +int m3pi::putc (int c) { + return(_ser.putc(c)); +} + +int m3pi::getc (void) { + return(_ser.getc()); +} + + + + + +#ifdef MBED_RPC +const rpc_method *m3pi::get_rpc_methods() { + static const rpc_method rpc_methods[] = {{ "forward", rpc_method_caller<m3pi, float, &m3pi::forward> }, + { "backward", rpc_method_caller<m3pi, float, &m3pi::backward> }, + { "left", rpc_method_caller<m3pi, float, &m3pi::left> }, + { "right", rpc_method_caller<m3pi, float, &m3pi::right> }, + { "stop", rpc_method_caller<m3pi, &m3pi::stop> }, + { "left_motor", rpc_method_caller<m3pi, float, &m3pi::left_motor> }, + { "right_motor", rpc_method_caller<m3pi, float, &m3pi::right_motor> }, + { "battery", rpc_method_caller<float, m3pi, &m3pi::battery> }, + { "line_position", rpc_method_caller<float, m3pi, &m3pi::line_position> }, + { "sensor_auto_calibrate", rpc_method_caller<char, m3pi, &m3pi::sensor_auto_calibrate> }, + + + RPC_METHOD_SUPER(Base) + }; + return rpc_methods; +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/m3pi/m3pi.h Wed Apr 04 17:07:49 2012 +0000 @@ -0,0 +1,247 @@ +/* mbed m3pi Library + * Copyright (c) 2007-2010 cstyles + * + * 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 M3PI_H +#define M3PI_H + +#include "mbed.h" +#include "platform.h" + +#ifdef MBED_RPC +#include "rpc.h" +#endif + +#define SEND_SIGNATURE 0x81 +#define SEND_RAW_SENSOR_VALUES 0x86 +#define SEND_TRIMPOT 0xB0 +#define SEND_BATTERY_MILLIVOLTS 0xB1 +#define DO_PLAY 0xB3 +#define PI_CALIBRATE 0xB4 +#define DO_CLEAR 0xB7 +#define DO_PRINT 0xB8 +#define DO_LCD_GOTO_XY 0xB9 +#define LINE_SENSORS_RESET_CALIBRATION 0xB5 +#define SEND_LINE_POSITION 0xB6 +#define AUTO_CALIBRATE 0xBA +#define SET_PID 0xBB +#define STOP_PID 0xBC +#define M1_FORWARD 0xC1 +#define M1_BACKWARD 0xC2 +#define M2_FORWARD 0xC5 +#define M2_BACKWARD 0xC6 + + + +/** m3pi control class + * + * Example: + * @code + * // Drive the m3pi forward, turn left, back, turn right, at half speed for half a second + + #include "mbed.h" + #include "m3pi.h" + + m3pi pi; + + int main() { + + wait(0.5); + + pi.forward(0.5); + wait (0.5); + pi.left(0.5); + wait (0.5); + pi.backward(0.5); + wait (0.5); + pi.right(0.5); + wait (0.5); + + pi.stop(); + + } + * @endcode + */ +class m3pi : public Stream { + + // Public functions +public: + + /** Create the m3pi object connected to the default pins + * + * @param nrst GPIO pin used for reset. Default is p23 + * @param tx Serial transmit pin. Default is p9 + * @param rx Serial receive pin. Default is p10 + */ + m3pi(); + + + /** Create the m3pi object connected to specific pins + * + */ + m3pi(PinName nrst, PinName tx, PinName rx); + + + + /** Force a hardware reset of the 3pi + */ + void reset (void); + + /** Directly control the speed and direction of the left motor + * + * @param speed A normalised number -1.0 - 1.0 represents the full range. + */ + void left_motor (float speed); + + /** Directly control the speed and direction of the right motor + * + * @param speed A normalised number -1.0 - 1.0 represents the full range. + */ + void right_motor (float speed); + + /** Drive both motors forward as the same speed + * + * @param speed A normalised number 0 - 1.0 represents the full range. + */ + void forward (float speed); + + /** Drive both motors backward as the same speed + * + * @param speed A normalised number 0 - 1.0 represents the full range. + */ + void backward (float speed); + + /** Drive left motor backwards and right motor forwards at the same speed to turn on the spot + * + * @param speed A normalised number 0 - 1.0 represents the full range. + */ + void left (float speed); + + /** Drive left motor forward and right motor backwards at the same speed to turn on the spot + * @param speed A normalised number 0 - 1.0 represents the full range. + */ + void right (float speed); + + /** Stop both motors + * + */ + void stop (void); + + /** Read the voltage of the potentiometer on the 3pi + * @returns voltage as a float + * + */ + float pot_voltage(void); + + /** Read the battery voltage on the 3pi + * @returns battery voltage as a float + */ + float battery(void); + + /** Read the position of the detected line + * @returns position as A normalised number -1.0 - 1.0 represents the full range. + * -1.0 means line is on the left, or the line has been lost + * 0.0 means the line is in the middle + * 1.0 means the line is on the right + */ + float line_position (void); + + + /** Calibrate the sensors. This turns the robot left then right, looking for a line + * + */ + char sensor_auto_calibrate (void); + + /** Set calibration manually to the current settings. + * + */ + void calibrate(void); + + /** Clear the current calibration settings + * + */ + void reset_calibration (void); + + void PID_start(int max_speed, int a, int b, int c, int d); + + void PID_stop(); + + /** Write to the 8 LEDs + * + * @param leds An 8 bit value to put on the LEDs + */ + void leds(int val); + + /** Locate the cursor on the 8x2 LCD + * + * @param x The horizontal position, from 0 to 7 + * @param y The vertical position, from 0 to 1 + */ + void locate(int x, int y); + + /** Clear the LCD + * + */ + void cls(void); + + /** Send a character directly to the 3pi serial interface + * @param c The character to send to the 3pi + */ + int putc(int c); + + /** Receive a character directly to the 3pi serial interface + * @returns c The character received from the 3pi + */ + int getc(); + + /** Send a string buffer to the 3pi serial interface + * @param text A pointer to a char array + * @param int The character to send to the 3pi + */ + int print(char* text, int length); + + struct LineSensors { + uint16_t sensor1; + uint16_t sensor2; + uint16_t sensor3; + uint16_t sensor4; + uint16_t sensor5; + }; + + const LineSensors get_raw_sensors(void); + + +#ifdef MBED_RPC + virtual const struct rpc_method *get_rpc_methods(); +#endif + +private : + + DigitalOut _nrst; + Serial _ser; + + void motor (int motor, float speed); + virtual int _putc(int c); + virtual int _getc(); + +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Wed Apr 04 17:07:49 2012 +0000 @@ -0,0 +1,107 @@ +#include "mbed.h" +#include "m3pi.h" +#include "MODSERIAL.h" + +#include "tlc5916.h" +#include "IRObjDetector.h" +#include "IRBehaviorController.h" +#include "Beacon.h" +#include "PID.h" + +DigitalOut led1(LED1); +DigitalOut led2(LED2); + +//Serial blueTooth(p13, p14); +MODSERIAL blueTooth(p13, p14); +Ticker taskTimer; +m3pi base; + +// PID terms +#define P_TERM 0.04f +#define I_TERM 0.00f +#define D_TERM 0.00f +#define THRESHOLD 0.30f +//PID pid(P_TERM, I_TERM, D_TERM, &blueTooth); +PID pid(P_TERM, I_TERM, D_TERM); +//IRObjDetector ird(&blueTooth); +//IRBehaviorController irController(&pid, &blueTooth); +IRBehaviorController irController(&pid); +Beacon beacon; + + +void +taskFunc(void) +{ +// blueTooth.printf("\e[1J"); // Clear terminal screen +// blueTooth.printf("\e[H"); // Home terminal screen +// blueTooth.printf("Task exec.\r\n"); + //irController.runSeeking(); + irController.runAvoidance(); + led1 = !led1; +} + +int +main() +{ + float power = 0.00f; + float speed = 0.20f; + float max = 1.00f; + float right, left; + + //FunctionPointer ird_scan(&ird, &IRObjDetector::scan); + + + base.reset(); + base.locate(0, 0); + base.printf("IR Track"); + wait(10); + + blueTooth.baud(115200); + blueTooth.printf("\r\nSystem start!\r\n"); + + irController.setActiveThreshold(THRESHOLD); + + //taskTimer.attach(&irController, &IRBehaviorController::runSeeking, 0.1); + taskTimer.attach(&taskFunc, 0.01); + + while(1) + { + blueTooth.printf("\e[1J"); // Clear terminal screen + blueTooth.printf("\e[H"); // Home terminal screen + blueTooth.printf("Main Loop Start.\r\n"); + blueTooth.printf("MAIN: Battery Voltage:\t%1.2f\r\n", base.battery()); + + pid.dumpDebug(&blueTooth); + irController.dumpDebug(&blueTooth); + + power = irController.getPower(); + + + right = speed - power; + left = speed + power; + + if (right < -max) + right = -max; + if (right > max) + right = max; + + if (left < -max) + left = -max; + if (left > max) + left = max; + + blueTooth.printf("MAIN: power = %3.2f\r\n", power); + blueTooth.printf("MAIN: speed = %3.2f\r\n", speed); + blueTooth.printf("MAIN: left = %3.2f\r\n", left); + blueTooth.printf("MAIN: right = %3.2f\r\n", right); + + base.left_motor(left); + base.right_motor(right); + + blueTooth.printf("Main Loop End.\r\n"); + wait(0.1); + }; + +// testIRObjDet(); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.lib Wed Apr 04 17:07:49 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/projects/libraries/svn/mbed/trunk@43 \ No newline at end of file